package com.sz.biz.logistics.ord.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sz.biz.common.base.dto.AreaDto;
import com.sz.biz.common.base.entity.MessageTemplate;
import com.sz.biz.common.base.service.AreaService;
import com.sz.biz.common.base.service.MessageTemplateService;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.common.constants.ModuleNames;
import com.sz.biz.common.customer.dto.CusCustomerOrderMessageDto;
import com.sz.biz.common.customer.dto.CusUserAddressDto;
import com.sz.biz.common.customer.dto.CustomerMessageDto;
import com.sz.biz.common.customer.dto.CustomerNoticeMessageTypeEnum;
import com.sz.biz.common.customer.entity.*;
import com.sz.biz.common.customer.service.*;
import com.sz.biz.common.sup.entity.Supplier;
import com.sz.biz.common.sup.service.SupplierService;
import com.sz.biz.common.utils.OrderMake;
import com.sz.biz.csr.entity.CsrWorkOrderSchema;
import com.sz.biz.csr.service.CsrWorkOrderSchemaService;
import com.sz.biz.logistics.base.entity.Airport;
import com.sz.biz.logistics.base.entity.Port;
import com.sz.biz.logistics.base.service.AirportService;
import com.sz.biz.logistics.base.service.PortService;
import com.sz.biz.logistics.billing.dto.QuotationCalcResult;
import com.sz.biz.logistics.billing.service.QuotationCalcService;
import com.sz.biz.logistics.constants.ErrorCodes;
import com.sz.biz.logistics.core.dto.*;
import com.sz.biz.logistics.core.entity.*;
import com.sz.biz.logistics.core.service.*;
import com.sz.biz.logistics.ord.constants.OrderConstants;
import com.sz.biz.logistics.ord.constants.OrderTrackingConstants;
import com.sz.biz.logistics.ord.dto.*;
import com.sz.biz.logistics.ord.entity.*;
import com.sz.biz.logistics.ord.enums.OrdOperationLogEnum;
import com.sz.biz.logistics.ord.enums.TrackMessageToServiceEnum;
import com.sz.biz.logistics.ord.service.*;
import com.sz.biz.logistics.serialno.constants.BillNumberConstants;
import com.sz.biz.logistics.serialno.entity.SerialNoManagement;
import com.sz.biz.logistics.serialno.service.NoManagementService;
import com.sz.biz.pay.constants.PayStatus;
import com.sz.common.base.cache.redis.RedisPoolManager;
import com.sz.common.base.constants.UserActions;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.CommonModel;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.i18n.I18nMessageHelper;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.*;
import com.sz.common.core.service.PrincipalLogUtils;
import com.sz.common.core.service.PrincipalUtils;
import com.sz.common.core.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Function: 产品订单 <br>
 * Author: hpeng.wang. <br>
 * Date: 2017-03-31 13:53:00.
 */
@org.springframework.stereotype.Service("ordOrderService")
public class OrdOrderServiceImpl extends AbstractService implements OrdOrderService {
    private static final String REGEX = "(\\[[^\\]]*\\])";

    @Autowired
    private OrdOrderAddressService orderAddressService;
    @Autowired
    private NoManagementService noManagementService;
    @Autowired
    private OrdSubOrderService subOrderService;
    @Autowired
    private OrdOrderCargoService orderCargoService;
    @Autowired
    private OrdOrderAdditionalService orderAdditionalService;
    @Autowired
    private OrdOrderFeeService orderFeeService;
    @Autowired
    private CustomerUserService customerUserService;
    @Autowired
    private ProductGroupService productGroupService;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private OrdOrderTrackingService orderTrackingService;
    @Autowired
    private OrdTrackingMessageService trackingMessageService;
    @Autowired
    private AreaService areaService;
    @Autowired
    private ProductServiceRelService productServiceRelService;
    @Autowired
    private ProductService productService;
    @Autowired
    private ProductCargoTypeRelService productCargoTypeRelService;
    @Autowired
    private ServiceService serviceService;
    @Autowired
    private SysUserSupport sysUserSupport;
    @Autowired
    private SysDictService dictService;
    @Autowired
    private OrdOrderStatusCodeService orderStatusCodeService;
    @Autowired
    private QuotationCalcService calcService;
    @Autowired
    private OrdOrderFileService orderFileService;
    @Autowired
    private CustomerMessageRelService customerMessageRelService;
    @Autowired
    private SysMailService sysMailService;
    @Autowired
    private SupplierService supplierService;
    @Autowired
    private SysSmsService sysSmsService;
    @Autowired
    private MessageTemplateService messageTemplateService;
    @Autowired
    private CusCustomerOrderMessageService cusCustomerOrderMessageService;
    @Autowired
    private BizOperationLogService operationLogService;
    @Autowired
    private OrdOrderServiceAssignService orderServiceAssignService;
    @Autowired
    private CustomerUserAddressService customerUserAddressService;
    @Autowired
    private PortService portService;
    @Autowired
    private AirportService airportService;
    @Autowired
    private CsrWorkOrderSchemaService workOrderSchemaService;
    @Value("${customer.service.hotline}")
    private String phone;



    @Override
    protected String getMapperNamespace() {
        return "com.sz.biz.logistics.ord.entity.mapper.OrdOrderMapper";
    }

    /**
     * 保存订单
     *
     * @param dto 新增的实体dto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String saveOrderDto(OrdOrderDto dto) {

        String orderNo = "";
        if (!ObjectUtils.isEmpty(dto)) {
            //向dto中设置订单创建者的信息，后面会用到。
            dto.setCreateUserId(PrincipalUtils.getAccountId());
            dto.setLastUpdateUserId(PrincipalUtils.getAccountId());
            //1、保存订单
            OrdOrder order = new OrdOrder();
            EntityUtils.copyPropertiesIgnoreNull(dto, order);
            //生成订单号,
            //2017-11 add by xiaoyanhong。 朱雯的需求更改，无论运营平台还是客户平台，没有草稿单号了，统一用正式单号。
            order.setOrderNo(OrderMake.generateOrderNo());
            dto.setOrderNo(order.getOrderNo());//将生成的订单号设置到dto中的orderNo中
            orderNo = order.getOrderNo();
            //2、处理订单的地址
            OrdOrderAddress ordOrderAddress = new OrdOrderAddress();//订单的地址信息
            ProductGroup productGroup = productService.findGroupByUid(order.getProductUid());

            int groupId = productGroup.getParentId();
            if (groupId != CommCodes.TRANSPORT_AIR && groupId != CommCodes.TRANSPORT_SEA) {
                groupId = CommCodes.TRANSPORT_LAND;
            }


            if (!ObjectUtils.isEmpty(dto.getFromAddress())) {
                dto.getFromAddress().setTransportType(groupId);
            }
            if (!ObjectUtils.isEmpty(dto.getToAddress())) {
                dto.getToAddress().setTransportType(groupId);
            }
            this.setAddress(dto, ordOrderAddress);
            //校验提货地址
            this.judgeFetchAddress(dto, ordOrderAddress);

            CusUser cusUser = customerUserService.findById(order.getCusUserId());
            if (ObjectUtils.isEmpty(cusUser)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "根据用户id不能找到对应的客户");
            }
            //订单的结算方式，跟客户的结算方式一致:现结，月结等
            CusCustomer customer = customerService.findCustomerById(order.getCustomerId());
            if (!ObjectUtils.isEmpty(customer)) {
                order.setSettlementTypeId(customer.getRefSettlementId());
            }
            //用户 关联的 客户id
            order.setCustomerId(cusUser.getRefCustomerId());
            dto.setCustomerId(order.getCustomerId());//因为下面要用到
            this.validated(order, ordOrderAddress);
            //检查附件
            orderFileService.checkFile(dto.getOrderStatus(), dto.getFileDtos());
            // TODO 调用 现结客户支付 完成后提供的接口，更新订单支付状态


            //附件信息添加add by yanhong.xiao  2017-08-07 增加附件数据  start
            Integer createUserType;
            if (order.getType().intValue() == OrderConstants.OrderPlatform.ORDER_OPERATOR) {
                createUserType = CommCodes.OPERATOR_USER_TYPE;
            } else {
                createUserType = CommCodes.CUSTOMER_USER_TYPE;
            }
            orderFileService.saveOrdFiles(createUserType, order.getOrderNo(), dto.getOrderStatus(), dto.getFileDtos());


            //如果订单为自动受理并且为提交状态，那么更新订单的状态为已受理
            int acceptType = productService.getProductAcceptType(dto.getProductUid());
            if (acceptType == CommCodes.PRODUCT_ACCETP_TYPE_AUTO && dto.getOrderStatus() == OrderStatus.COMMITED) {
                dto.setOrderStatus(OrderStatus.ACCEPT);
                order.setOrderStatus(OrderStatus.ACCEPT);
            }
            //订单保存时，设置运单号
            SerialNoManagement serialNoManagement = null;
            long oldNumberId = 0L;
            if (dto.getOrderStatus().compareTo(OrderStatus.COMMITED) >= 0) {//当订单的状态大于等于已提交时，就要生成运单号
                serialNoManagement = this.handleWaybillNo(orderNo, order.getWaybillNo(), dto.getProductUid(), productGroup.getId(), order.getCustomerId(), 0L);
                order.setWaybillNo(serialNoManagement.getSerialNumber());
                dto.setWaybillNo(serialNoManagement.getSerialNumber());
                oldNumberId = serialNoManagement.getId();
            } else {
                String waybillNo = OrderMake.generateDraftWaybillNo();
                order.setWaybillNo(waybillNo);
                dto.setWaybillNo(waybillNo);
            }
            boolean bSaved = this.trySaveOrder(order, productGroup, oldNumberId);
            if (!bSaved) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单保存异常，请核实");
            } else {
                dto.setWaybillNo(order.getWaybillNo());
            }

            //4、保存订单的地址信息
            orderAddressService.save(ordOrderAddress);

            //5、处理订单其它数据：子单、货物、可选服务信息，并返回子单编号
            this.processOther(dto);

            //6、非草稿状态时，处理子单物流信息，分派服务、费用预估。
            if (dto.getOrderStatus().compareTo(OrderStatus.COMMITED) >= 0) {
                //1、只在非草稿状态下才会处理子订单
                List<String> subOrderNos = subOrderService.saveSubOrders(dto.getOrderNo(), dto.getWaybillNo(), dto.getPackageNum(), dto.getOrderStatus());
                subOrderService.batchAddSubTracking(order.getOrderNo(), order.getWaybillNo(), order.getOrderStatus(), subOrderNos);
                orderFeeService.submitBillByAccept(order.getOrderNo());
            }


            //7、添加日志信息
            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("ADD_ORD_ORDER", dto);
            PrincipalLogUtils.addOperationLog(ModuleNames.ORD, ModuleNames.ORD_ORDER, UserActions.ADD, "新增订单", dataBackup);

            //8，异步添加订单的操作日志信息 add 2017-10
            OrdOperationLogEnum eventTypeEnum = getOrdOperationLogEnum(order.getOrderStatus());
            operationLogService.saveOrdOperLogForDraftOrCommit(Arrays.asList(order.getId()), PrincipalUtils.getAccountId(), PrincipalUtils.getDomainId(), eventTypeEnum);
        }

        return orderNo;
    }

    /**
     * 多请尝试获取运单号，保存订单
     *
     * @param order        订单信息
     * @param productGroup 产品组信息
     * @param oldNumberId
     */
    private boolean trySaveOrder(OrdOrder order, ProductGroup productGroup, long oldNumberId) {
        //3、保存订单
        boolean bSaved = false;
        int count = 0;
        String action = "保存订单异常!";
        while (!bSaved && count <= 10) {
            try {
                this.save(order);
                bSaved = true;
            } catch (Exception ex) {
                String message = ex.getCause().getMessage();
                if ((message.contains("Duplicate entry") && message.contains("waybillNo"))) {
                    logger.error(action + order.getWaybillNo());
                    if (order.getOrderStatus().compareTo(OrderStatus.COMMITED) >= 0) {
                        SerialNoManagement serialNoManagement = this.handleWaybillNo(order.getOrderNo(), order.getWaybillNo(), order.getProductUid(), productGroup.getId(), order.getCustomerId(), oldNumberId);
                        order.setWaybillNo(serialNoManagement.getSerialNumber());
                        oldNumberId = serialNoManagement.getId();
                    } else {
                        logger.error(action + order, ex);
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, action);
                    }
                } else {
                    logger.error(action + order, ex);
                    throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, action);
                }
                count++;
            }
        }

        if (count > 10) {
            logger.error("多次尝试仍然没有成功，请核实：" + order);
        }
        return bSaved;
    }


    private boolean tryUpdateOrder(OrdOrder order, boolean bUpdateWaybillNo, long oldNumberId) {
        //3、保存订单
        boolean bUpdated = false;
        int count = 0;
        String action = "更新订单异常!";
        while (!bUpdated && count <= 10) {
            try {
                this.update(order);
                bUpdated = true;
            } catch (Exception ex) {
                String message = ex.getCause().getMessage();
                if (message.contains("Duplicate entry") && message.contains("waybillNo")) {
                    logger.error(action + order.getWaybillNo());
                    //当订单状态从草稿变成已提交时，这时要把运单号进行生成
                    if (bUpdateWaybillNo) {//当订单的状态大于等于已提交时，就要生成运单号
                        SerialNoManagement serialNoManagement = this.handleWaybillNo(order.getOrderNo(), order.getProductUid(), order.getCustomerId(), oldNumberId);
                        order.setWaybillNo(serialNoManagement.getSerialNumber());
                        oldNumberId = serialNoManagement.getId();
                    } else {
                        logger.error(action + order, ex);
                        throw Exceptions.bizException(ErrorCodes.ERROR_ORD_WAYBILLNO_UPDATE_EXCEPTION);
                    }
                } else {
                    logger.error(action + order, ex);
                    throw Exceptions.bizException(ErrorCodes.ERROR_ORD_WAYBILLNO_UPDATE_EXCEPTION);
                }
                count++;
            }
        }

        if (count > 10) {
            logger.error("多次尝试仍然没有成功，请核实：" + order);
        }
        return bUpdated;
    }

    private OrdOperationLogEnum getOrdOperationLogEnum(OrderStatus orderStatus) {
        OrdOperationLogEnum eventTypeEnum;
        if (orderStatus == OrderStatus.DRAFT) {
            eventTypeEnum = OrdOperationLogEnum.CREATE_DRAFT;//草稿
        } else if (orderStatus == OrderStatus.ACCEPT) {
            eventTypeEnum = OrdOperationLogEnum.ACCEPT_ORDER;//受理
        } else {
            eventTypeEnum = OrdOperationLogEnum.SUBMIT_ORDER;//提交
        }
        return eventTypeEnum;
    }

    @Override
    public void batchSaveOrder(List<OrdOrder> ordOrderList, List<SerialNoManagement> serialNoManagementList) {
        Map<String, SerialNoManagement> stringSerialNoManagementMap = EntityUtils.getStringKeyMapFromBeans(serialNoManagementList, "orderNumber");
        if (!CollectionUtils.isEmpty(ordOrderList)) {
            boolean bSaved = false;
            while (!bSaved) {
                try {
                    dao.save(getSqlName("insert"), ordOrderList);
                    //dao.batchInsert(getSqlName("insert"),ordOrderList);
                    bSaved = true;
                } catch (Exception e) {
                    String message = e.getCause().getMessage();
                    //String message = e.getCause().getCause().getMessage();
                    if (message.contains("Duplicate entry") && message.contains("waybillNo_UNIQUE")) {
                        String waybillNo = processWaybillNo(message);
                        for (OrdOrder order : ordOrderList) {
                            if (order.getWaybillNo().equals(waybillNo)) {
                                SerialNoManagement serialNoManagement = stringSerialNoManagementMap.get(order.getOrderNo());
                                serialNoManagement = this.handleWaybillNo(order.getOrderNo(), order.getProductUid(), order.getCustomerId(), serialNoManagement.getId());
                                stringSerialNoManagementMap.put(order.getOrderNo(), serialNoManagement);
                                order.setWaybillNo(serialNoManagement.getSerialNumber());
                                break;
                            }
                        }
                    } else {
                        logger.error("保存数据出错", e);
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "数据保存异常!");
                    }

                }
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void batchInsert(List<OrdOrder> ordOrderList) {
        dao.batchInsert(getSqlName("insert"), ordOrderList);
    }

    public static String processWaybillNo(String errorMessage) {
        String waybillNo = "";
        Pattern pattern = Pattern.compile("[\\w\\s]+'(\\d+)'[\\w\\s'\\d]+");
        Matcher matcher = pattern.matcher(errorMessage);

        while (matcher.find()) {
            waybillNo = matcher.group(1);
        }
        return waybillNo;
    }

    /**
     * 获取运单号
     *
     * @param orderNo            订单号
     * @param productUid         产品的uid
     * @param productGroupLeafId 产品组的id(叶子结点)
     * @return 获取到的运单号信息
     */
    private SerialNoManagement handleWaybillNo(String orderNo, String waybillNo, String productUid, int productGroupLeafId, int customerId, long oldNumberId) {
        //当传递渠道单号时
        SerialNoManagement serialNoManagement = null;
        if (!StringUtils.isEmpty(waybillNo)) {
            boolean isValid = noManagementService.checkIsLegal(productUid, productGroupLeafId, waybillNo, BillNumberConstants.NumberType.WAYBILL_NUMBER, orderNo);
            if (isValid) {
                serialNoManagement = new SerialNoManagement();
                serialNoManagement.setSerialNumber(waybillNo);
                return serialNoManagement;
            }
        }
        //当没有传递运单号或运单号不符合规则时
        try {
            serialNoManagement = noManagementService.useWaybillNo(productUid, productGroupLeafId, orderNo, customerId, oldNumberId);
            if (StringUtils.isEmpty(serialNoManagement)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_ORD_WAYBILLNO_GET_EXCEPTION);
            }

        } catch (Exception ex) {
            logger.error("获取单号异常", ex);
            throw Exceptions.bizException(ErrorCodes.ERROR_ORD_WAYBILLNO_GET_EXCEPTION);
        }
        return serialNoManagement;

    }

    private SerialNoManagement handleWaybillNo(String orderNo, String productUid, int customerId, long oldNumberId) {
        SerialNoManagement serialNoManagement = null;
        ProductGroup productGroup = productService.findGroupByUid(productUid);
        int productGroupLeafId;
        if (!ObjectUtils.isEmpty(productGroup)) {
            productGroupLeafId = productGroup.getId();
            serialNoManagement = this.handleWaybillNo(orderNo, null, productUid, productGroupLeafId, customerId, oldNumberId);
        }

        return serialNoManagement;

    }

    /**
     * 保存客户的用户的地址(收件地址、发件地址、揽收地址)
     *
     * @param dto 要处理的orderdto
     * @return
     */
    @Override
    public void saveCusUserAddress(OrdOrderDto dto) throws Exception {
        CusUserAddressDto addressDto;

        if (dto.getFromAddress() != null && dto.getFromAddress().isSyncAddress()) {//保存发件人地址
            addressDto = new CusUserAddressDto();
            EntityUtils.copyPropertiesIgnoreNull(dto.getFromAddress(), addressDto);

            addressDto.setCustomerId(dto.getCusUserId());
            addressDto.setName(dto.getFromName());
            addressDto.setPhone(dto.getFromPhone());
            addressDto.setTelPhone(dto.getFromTelephone());
            addressDto.setType(AddressTypeEnum.SENDADDRESS.getCode());//发件人

            customerUserAddressService.saveOrUpdate(addressDto);
        }
        if (dto.getToAddress() != null && dto.getToAddress().isSyncAddress()) {//保存收件人地址
            addressDto = new CusUserAddressDto();
            EntityUtils.copyPropertiesIgnoreNull(dto.getToAddress(), addressDto);

            addressDto.setCustomerId(dto.getCusUserId());
            addressDto.setName(dto.getToName());
            addressDto.setPhone(dto.getToPhone());
            addressDto.setTelPhone(dto.getToTelephone());
            addressDto.setType(AddressTypeEnum.RECEIVERADDRESS.getCode());//收件人

            customerUserAddressService.saveOrUpdate(addressDto);
        }
        if (dto.getFetchAddress() != null && dto.getFetchAddress().isSyncAddress()) {//保存揽收地址
            addressDto = new CusUserAddressDto();
            EntityUtils.copyPropertiesIgnoreNull(dto.getFetchAddress(), addressDto);

            addressDto.setCustomerId(dto.getCusUserId());
            addressDto.setName(dto.getFetchName());
            addressDto.setPhone(dto.getFetchPhone());
            addressDto.setTelPhone(dto.getFetchTelephone());
            addressDto.setType(AddressTypeEnum.PICKADDRESS.getCode());//揽货类型

            customerUserAddressService.saveOrUpdate(addressDto);
        }
    }

    private void judgeFetchAddress(OrdOrderDto dto, OrdOrderAddress ordOrderAddress) {
        String fetchName = dto.getFetchName() == null ? "" : dto.getFetchName();
        boolean bOk = this.isExistOptionService(dto.getOrderAdditionalDtos(), dto.getProductUid());


        if (!bOk && !StringUtils.isEmpty(fetchName)) {//如果当前订单没有揽收服务，但是传了提货地址，应为异常
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "产品未包含揽收服务，不应有提货地址！");
        }

        if (bOk && StringUtils.isEmpty(fetchName)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "提货联系人的地址未找到，请添加!");
        }

        //  判断客户提交的揽收地址是否在揽收服务的地址范围内
        if (bOk) {
            //获取可选服务的uid集合
            List<ProductAddressDto> productAddressDtoList = productService.getProductAddress(dto.getProductUid(), CommCodes.PRODUCT_SERVICE_REGION_PICKUP);
            ProductAddressDto productAddressDto = new ProductAddressDto();
            productAddressDto.setCountry(ordOrderAddress.getFetchCountry());
            productAddressDto.setProvince(ordOrderAddress.getFetchProvince());
            productAddressDto.setCity(ordOrderAddress.getFetchCity());
            productAddressDto.setArea(ordOrderAddress.getFetchDistrict());
            productAddressDto.setStreet(ordOrderAddress.getFetchStreet());
            productAddressDto.setTransportType(CommCodes.TRANSPORT_LAND);
            productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_PICKUP);
            boolean isOk = productService.checkProductAddress(productAddressDtoList, productAddressDto);
            if (!isOk) {//有不合适的
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, CommCodes.FETCH_ADDRESS_NOT_IN_SERVICE_SCOPE);
            }
        }
    }

    @Override
    public void batchDeleteByOrderNos(List<String> orderNos) {
        if (!CollectionUtils.isEmpty(orderNos)) {
            //1、校验订单是否为草稿状态
            List<OrdOrder> ordOrderList = this.findByOrderNos(orderNos);
            for (OrdOrder order : ordOrderList) {
                if (order.getOrderStatus() != OrderStatus.DRAFT) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要删除的订单号：" + order.getOrderNo() + "，为非草稿的状态!");
                }
            }
            //2、数据备份
            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("DELETE_ORD_ORDER", orderNos);
            PrincipalLogUtils.addOperationLog(ModuleNames.ORD, ModuleNames.ORD_ORDER, UserActions.DELETE, "删除订单", dataBackup);
            //3、删除数据
            dao.update(getSqlName("updateByOrderNo"), orderNos);
        }
    }

    /**
     * 客户系统修改订单.
     * 1. 检查订单是否存在
     * 2. 检查是否是自己修改自己的订单,(自己不允许修改别人的订单)
     * 3. 校验订单的可操作性
     * 4. 组装新的order
     * 5. 校验数据有效性,产品，客户，货物类型，重量范围，地址，外部单号
     * 6. 处理寄件人地址和收货人地址
     * <p>
     * 7.判断是否有新的订单号需要
     * 8. 处理货物明细（考虑订单状态是否从草稿到已提交，产生新的订单号）
     * 9. 处理附加服务(考虑订单状态是否从草稿到已提交，产生新的订单号)
     * 10. 处理子单（考虑订单状态是否从草稿到已提交，处理物流信息）
     * 11.处理物流信息
     * 12.修改订单信息
     * 13. 数据备份
     *
     * @param orderDto
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateByDto(OrdOrderDto orderDto, String userType) {
        if (!ObjectUtils.isEmpty(orderDto) && StringUtils.hasLength(userType)) {
            boolean bUpdateWaybillNo = false;
            orderDto.setLastUpdateUserId(PrincipalUtils.getAccountId());

            //1、检查订单是否存在
            OrdOrder order = this.findByOrderNo(orderDto.getOrderNo());
            if (ObjectUtils.isEmpty(order)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要修改的订单不存在");
            }
            //当订单状态从草稿变成已提交时，这时要把运单号进行生成
            long oldNumberId = 0;
            if (OrderStatus.DRAFT == order.getOrderStatus() && (OrderStatus.COMMITED == orderDto.getOrderStatus() || OrderStatus.ACCEPT == orderDto.getOrderStatus())) {//当订单的状态大于等于已提交时，就要生成运单号
                SerialNoManagement serialNoManagement = this.handleWaybillNo(order.getOrderNo(), order.getProductUid(), order.getCustomerId(), 0L);
                orderDto.setWaybillNo(serialNoManagement.getSerialNumber());
                oldNumberId = serialNoManagement.getId();
                bUpdateWaybillNo = true;
            }

            //如果订单为自动受理并且为提交状态，那么更新订单的状态为已受理
            int acceptType = productService.getProductAcceptType(orderDto.getProductUid());
            if (acceptType == CommCodes.PRODUCT_ACCETP_TYPE_AUTO && orderDto.getOrderStatus() == OrderStatus.COMMITED) {
                orderDto.setOrderStatus(OrderStatus.ACCEPT);
            }

            //原来的地址
            OrdOrderDto oldOrderDto = this.findDtoByOrderNo(orderDto.getOrderNo());
            OrdOrderAddress oldOrdOrderAddress = orderAddressService.findByOrderNo(orderDto.getOrderNo());
            oldOrderDto.setFromDetail(oldOrdOrderAddress.getFromDetail());
            oldOrderDto.setToDetail(oldOrdOrderAddress.getToDetail());
            oldOrderDto.setFetchDetail(oldOrdOrderAddress.getFetchDetail());


            CusUser cusUser = customerUserService.findById(order.getCusUserId());
            if (ObjectUtils.isEmpty(cusUser)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "根据用户id不能找到对应的客户");
            }
            orderDto.setCustomerId(cusUser.getRefCustomerId());
            int origPackageNum = order.getPackageNum();//记录原来的packageNum
            OrderStatus origOrderStatus = order.getOrderStatus();
            //2、判断是否需要生成新的订单号
            //add 2017-11 修改时不需要再修改客户系统的草稿订单号
            //3、校验订单的可操作性
            this.judgeOperate(order, orderDto, userType);
            //4、更新订单的信息
            orderDto.setType(null);//订单的type不应被替换掉
            orderDto.setId(null);//更新时id不应被变对
            EntityUtils.copyPropertiesIgnoreNull(orderDto, order);
            //5、处理订单的地址信息
            OrdOrderAddress ordOrderAddress = orderAddressService.findByOrderNo(orderDto.getOrderNo());
            this.setAddress(orderDto, ordOrderAddress);//组装订单的地址信息
            this.judgeFetchAddress(orderDto, ordOrderAddress);
            //6、校验订单数据有效性,产品，客户，货物类型，重量范围，地址，外部单号
            this.validated(order, ordOrderAddress);
            //7、更新订单信息(根据主键id)



            boolean bUpdated = this.tryUpdateOrder(order, bUpdateWaybillNo, oldNumberId);
            if (!bUpdated) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单更新异常，请核实");
            } else {
                orderDto.setWaybillNo(order.getWaybillNo());
            }
            // this.update(order);
            //8、更新订单关联的数据信息
            this.processOrderRelationInfo(orderDto, ordOrderAddress, origPackageNum, origOrderStatus, order);

            //9、订单计费与多服务分派

            if (orderDto.getOrderStatus().compareTo(OrderStatus.TRANSPORT) >= 0) {
                orderFeeService.submitBillByTransportAfter(order.getOrderNo());
            } else {
                orderFeeService.submitBill(order.getOrderNo());
            }


            //9、数据备份
            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("UPDATE_ORD_ORDER", orderDto);
            PrincipalLogUtils.addOperationLog(ModuleNames.ORD, ModuleNames.ORD_ORDER, UserActions.UPDATE, "修改订单", dataBackup);
            // 10 物流订单编辑操作日志的记录, add  2017-10 新需求
            orderDto.setFromDetail(ordOrderAddress.getFromDetail());
            orderDto.setToDetail(ordOrderAddress.getToDetail());
            orderDto.setFetchDetail(ordOrderAddress.getFetchDetail());
            Integer accountId = PrincipalUtils.getAccountId();
            Integer domainId = PrincipalUtils.getDomainId();
            List<Integer> orderIds = Lists.newArrayList();
            orderIds.add(order.getId());
            Map<Integer, OrdOrderDto> oldOrderDtoMap = Maps.newHashMap();
            oldOrderDtoMap.put(order.getId(), oldOrderDto);
            Map<Integer, OrdOrderDto> newOrderDtoMap = Maps.newHashMap();
            newOrderDtoMap.put(order.getId(), orderDto);
            //判断是修改还是提交订单
            if (orderDto.getOrderStatus().compareTo(oldOrderDto.getOrderStatus()) > 0 && orderDto.getOrderStatus() == OrderStatus.COMMITED) {
                //提交订单
                operationLogService.saveOrdOperLogForCommit(orderIds, oldOrderDtoMap, newOrderDtoMap, UserActions.UPDATE, accountId, domainId);
            } else {
                //订单修改
                operationLogService.saveOrdOperLogForUpdate(orderIds, oldOrderDtoMap, newOrderDtoMap, UserActions.UPDATE, accountId, domainId);
            }
        }
    }


    @Override
    public void update(OrdOrder order) {
        if (!ObjectUtils.isEmpty(order)) {
            this.batchUpdate(Arrays.asList(order));
        }
    }

    @Override
    public int batchUpdate(List<OrdOrder> orders) {
        int count = 0;
        if (!CollectionUtils.isEmpty(orders)) {
            count = dao.batchUpdate(getSqlName("updateByOrderNoSelective"), orders);
        }
        return count;
    }

    @Override
    public OrdOrder findByOrderNo(String orderNo) {
        return (OrdOrder) dao.findForObject(getSqlName("findByOrderNo"), orderNo);
    }

    @Override
    public List<String> findOrderNoByOrderStatus(OrderStatus orderStatus) {
        List<String> orderNos = new ArrayList<>();
        if (!ObjectUtils.isEmpty(orderStatus)) {
            orderNos = dao.findForList(getSqlName("findOrderNoByOrderStatus"), orderStatus, String.class);
        }
        return orderNos;
    }

    @Override
    public OrderStatus findOrderStatus(String orderNo) {
        OrderStatus orderStatus = null;
        OrdOrder order = (OrdOrder) dao.findForObject(getSqlName("findOrderStatus"), orderNo);
        if (!ObjectUtils.isEmpty(order)) {
            orderStatus = order.getOrderStatus();
        }
        return orderStatus;
    }

    @Override
    public OrdOrderDto findDtoByOrderNo(String orderNo) {
        OrdOrderDto orderDto = null;
        if (StringUtils.hasLength(orderNo)) {
            //1、根据运单编号集合（orderNoList）查询相应的产品订单（ordOrderList）、子订单(ordSubOrderList)、商品明细(ordOrderCargoList)
            OrdOrder ordOrder = this.findByOrderNo(orderNo);

            if (ObjectUtils.isEmpty(ordOrder)) {
                return null;
            }
            //显示时，如果是草稿状态，不显示运单号
            if (OrderStatus.DRAFT == ordOrder.getOrderStatus()) {
                ordOrder.setWaybillNo(null);
            }
            orderDto = new OrdOrderDto();
            //将ordOrder 拷贝 到 orderDto
            EntityUtils.copyPropertiesIgnoreNull(ordOrder, orderDto);
            //设置货物类型的名字
            Map<String, String> sysDictCargoTypeMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_CARGO_TYPE);
            Map<String, String> sysDictUnitWeightMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_UNIT_WEIGHT);
            orderDto.setCargoTypeName(sysDictCargoTypeMap.get(orderDto.getCargoType()));
            //设置订单状态的名字
            orderDto.setOrderStatusName(ordOrder.getOrderStatus().getName());
            orderDto.setCusWeightUnitName(sysDictUnitWeightMap.get(ordOrder.getCusWeightUnit()));
            orderDto.setFeeCalcWeightUnitName(sysDictUnitWeightMap.get(ordOrder.getFeeCalcWeightUnit()));
            orderDto.setSupWeightUnitName(sysDictUnitWeightMap.get(ordOrder.getSupWeightUnit()));
            orderDto.setVolumeWeightUnitName(sysDictUnitWeightMap.get(ordOrder.getVolumeWeightUnit()));


            //设置创建者的名字
            if (ordOrder.getType().intValue() == OrderConstants.OrderPlatform.ORDER_OPERATOR) {//平台代下单
                UserModel userModel = sysUserSupport.getUserById(ordOrder.getCreateUserId());
                if (!ObjectUtils.isEmpty(userModel)) {
                    orderDto.setCreateUserName(userModel.getAccountName());
                    orderDto.setCreateFullName(userModel.getFullName());
                }
            } else {//客户自己下单
                CusUser cusUser = customerUserService.findById(ordOrder.getCreateUserId());
                if (!ObjectUtils.isEmpty(cusUser)) {
                    orderDto.setCreateUserName(cusUser.getUserName());
                    orderDto.setCreateFullName(cusUser.getFullName());
                }
            }
            //设置产品的名字
            ProductDto productDto = productService.findActivedByUid(orderDto.getProductUid());
            if (!ObjectUtils.isEmpty(productDto)) {
                orderDto.setProductName(productDto.getName());
                orderDto.setProductId(productDto.getId());
                orderDto.setProductCode(productDto.getCode());
            }
            //设置客户账号的名字
            CusUser cusUser = customerUserService.findById(orderDto.getCusUserId());
            if (!ObjectUtils.isEmpty(cusUser)) {
                orderDto.setCusUserName(cusUser.getUserName());
            }

            //设置客户账号的名字
            CusCustomer customer = customerService.findShortById(orderDto.getCustomerId());
            if (!ObjectUtils.isEmpty(customer)) {
                orderDto.setCustomerName(customer.getUserName());
            }

            //设计订单地址信息
            OrdOrderAddress orderAddress = orderAddressService.findByOrderNo(orderNo);
            this.processAddress(orderDto, orderAddress, 1);

            //2.2、向ordOrderDto中设置商品明细的dto（ordOrderCargoDto）
            List<OrdOrderCargoDto> orderCargoDtos = orderCargoService.findDtoByOrderNo(orderNo);
            orderDto.setOrderCargoDtos(orderCargoDtos);

            //2.3、向ordOrderDto中设置子订单的dto（ordSubOrderDto）
            List<OrdSubOrderDto> subOrderDtoList = subOrderService.findDtoByOrderNo(orderNo);
            orderDto.setOrdSubOrderDtos(subOrderDtoList);

            //2.4、向orderDto中设置附加服务dto（OrdOrderAdditionalDto）
            List<OrdOrderAdditionalDto> orderAdditionalDtoList = orderAdditionalService.findDtoByOrderNo(orderNo);
            orderDto.setOrderAdditionalDtos(orderAdditionalDtoList);

            //2.5、向orderDto中设置订单费用dto（OrdOrderFeeDto）
            OrdOrderFeeDto orderFeeDto = orderFeeService.findDtoByOrderNo(orderNo);
            orderDto.setOrderFeeDto(orderFeeDto);


        }
        return orderDto;
    }

    /**
     * 根据运单号集合，批量获取信息
     *
     * @param orderNos
     * @return
     */
    @Override
    public List<OrdOrderDto> findDtosByOrderNos(List<String> orderNos) {
        orderNos = CollectionUtils.removeDuplication(orderNos);
        List<OrdOrder> ordOrderList = this.findByOrderNos(orderNos);
        //获取地址信息
        List<OrdOrderAddress> orderAddressList = orderAddressService.findByOrderNos(orderNos);
        Map<String, OrdOrderAddress> orderAddressMap = new HashMap<>();
        orderAddressList.forEach(orderAddress -> orderAddressMap.put(orderAddress.getOrderNo(), orderAddress));
        List<OrdOrderDto> dtos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(ordOrderList)) {
            //设置货物类型的名字
            Map<String, String> sysDictCargoTypeMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_CARGO_TYPE);
            Map<String, String> sysDictUnitWeightMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_UNIT_WEIGHT);
            List<String> productUidList = new ArrayList<>();
            List<Integer> cusUserIdList = new ArrayList<>();
            List<Integer> customerIdList = new ArrayList<>();
            ordOrderList.forEach(ordOrder -> {
                productUidList.add(ordOrder.getProductUid());
                cusUserIdList.add(ordOrder.getCusUserId());
                customerIdList.add(ordOrder.getCustomerId());
            });
            //获取产品的信息
            List<Product> productList = productService.findShortActivedByUids(Lists.newArrayList(new HashSet<String>(productUidList)));
            Map<String, String> productMap = new HashMap<>();
            productList.forEach(product -> productMap.put(product.getUid(), product.getName()));
            //获取客户的信息
            List<CusCustomer> customerList = customerService.findShortByIds(Lists.newArrayList(new HashSet<>(customerIdList)));
            Map<Integer, String> customerMap = new HashMap<>();
            customerList.forEach(cusCustomer -> customerMap.put(cusCustomer.getId(), cusCustomer.getUserName()));
            //获取用户的信息
            List<CusUser> cusUsers = customerUserService.findShortByIds(Lists.newArrayList(new HashSet<>(cusUserIdList)));
            Map<Integer, String> cusUserMap = new HashMap<>();
            cusUsers.forEach(cusUser -> cusUserMap.put(cusUser.getId(), cusUser.getUserName()));
            //获取明细
            Map<String, List<OrdOrderCargoDto>> cargoDtoMap = orderCargoService.findDtosByOrderNos(orderNos);
            //子单
            Map<String, List<OrdSubOrderDto>> subOrderDtoMap = subOrderService.findMapDtosByOrderNos(orderNos);
            //附加服务
            Map<String, List<OrdOrderAdditionalDto>> additionalDtoMap = orderAdditionalService.findMapDtosByOrderNos(orderNos);

            //2.5、向orderDto中设置订单费用dto（OrdOrderFeeDto）
            Map<String, OrdOrderFeeDto> feeDtoMap = orderFeeService.findMapDtosByOrderNos(orderNos);


            for (OrdOrder ordOrder : ordOrderList) {
                OrdOrderDto orderDto = new OrdOrderDto();
                EntityUtils.copyPropertiesIgnoreNull(ordOrder, orderDto);
                orderDto.setCargoTypeName(sysDictCargoTypeMap.get(orderDto.getCargoType()));
                //设置订单状态的名字
                orderDto.setOrderStatusName(ordOrder.getOrderStatus().getName());
                orderDto.setCusWeightUnitName(sysDictUnitWeightMap.get(ordOrder.getCusWeightUnit()));
                orderDto.setCustomerName(customerMap.get(ordOrder.getCustomerId()));
                orderDto.setCusUserName(cusUserMap.get(orderDto.getCusUserId()));
                orderDto.setProductName(productMap.get(orderDto.getProductUid()));
                //设置城市的名字
                this.processAddress(orderDto, orderAddressMap.get(ordOrder.getOrderNo()), 1);
                // 向ordOrderDto中设置商品明细的dto（ordOrderCargoDto）
                orderDto.setOrderCargoDtos(cargoDtoMap.get(orderDto.getOrderNo()));
                //向ordOrderDto中设置子订单的dto（ordSubOrderDto）
                orderDto.setOrdSubOrderDtos(subOrderDtoMap.get(orderDto.getOrderNo()));
                //向orderDto中设置附加服务dto（OrdOrderAdditionalDto）
                orderDto.setOrderAdditionalDtos(additionalDtoMap.get(orderDto.getOrderNo()));
                orderDto.setOrderFeeDto(feeDtoMap.get(orderDto.getOrderNo()));
                dtos.add(orderDto);
            }
        }
        return dtos;
    }

    @Override
    public QResultDto findDtoByParam(QueryParams params) {
        ParamData pd = convertQueryParams(params);
        //1、根据条件查询相应的运单编号
        List<OrdOrder> ordOrderList = dao.findForList(getSqlName("findByParamListPage"), pd, OrdOrder.class);
        Map<String, String> sysDictCargoTypeMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_CARGO_TYPE);
        //2、根据上面查询出来的信息拼装要返回给前端的dto集合信息（ordOrderDtoList）
        List<OrdOrderDto> ordOrderDtoList = new ArrayList<>();//存放拼装好的orderDto信息
        List<String> productUidList = new ArrayList<>();
        List<String> orderNoList = new ArrayList<>();
        List<Integer> cusUserIdList = new ArrayList<>();
        List<Integer> customerIdList = new ArrayList<>();
        List<CusCustomerOrderMessageDto> messageDtos = new ArrayList<>();
        for (OrdOrder ordOrder : ordOrderList) {
            productUidList.add(ordOrder.getProductUid());
            orderNoList.add(ordOrder.getOrderNo());
            cusUserIdList.add(ordOrder.getCusUserId());
            customerIdList.add(ordOrder.getCustomerId());
            ordOrder.getOrderStatus().getCode();
            messageDtos.add(new CusCustomerOrderMessageDto("1", ordOrder.getOrderNo(), ordOrder.getOrderStatus().getCode()));
        }
        productUidList = CollectionUtils.removeDuplication(productUidList);
        orderNoList = CollectionUtils.removeDuplication(orderNoList);
        cusUserIdList = CollectionUtils.removeDuplication(cusUserIdList);
        customerIdList = CollectionUtils.removeDuplication(customerIdList);
        List<OrdOrderAddress> orderAddressList = orderAddressService.findByOrderNos(orderNoList);
        List<CusCustomerOrderMessageDto> messageDtoList = cusCustomerOrderMessageService.queryOrdersResult(messageDtos);
        Map<String, CusCustomerOrderMessageDto> messageDtoMap = new HashMap<>();
        for (CusCustomerOrderMessageDto messageDto : messageDtoList) {
            String key = messageDto.getOrderNo() + "_" + messageDto.getOrderStatus();
            messageDtoMap.put(key, messageDto);
        }
        //获取地址信息
        Map<String, OrdOrderAddress> orderAddressMap = new HashMap<>();
        orderAddressList.forEach(orderAddress -> orderAddressMap.put(orderAddress.getOrderNo(), orderAddress));
        //获取产品的信息
        List<Product> productList = productService.findShortActivedByUids(productUidList);
        Map<String, String> productMap = new HashMap<>();
        productList.forEach(product -> productMap.put(product.getUid(), product.getName()));
        //获取客户的信息
        List<CusCustomer> customerList = customerService.findShortByIds(customerIdList);
        Map<Integer, String> customerMap = new HashMap<>();
        customerList.forEach(cusCustomer -> customerMap.put(cusCustomer.getId(), cusCustomer.getUserName()));
        //获取用户的信息
        List<CusUser> cusUsers = customerUserService.findShortByIds(cusUserIdList);
        Map<Integer, String> cusUserMap = new HashMap<>();
        cusUsers.forEach(cusUser -> cusUserMap.put(cusUser.getId(), cusUser.getUserName()));
        for (OrdOrder ordOrder : ordOrderList) {//向产品订单中设置子订单信息与商品明细信息
            //2.1、将ordOrder对象转成ordOrderDto对象
            OrdOrderDto orderDto = new OrdOrderDto();
            EntityUtils.copyPropertiesIgnoreNull(ordOrder, orderDto);
            orderDto.setCargoTypeName(sysDictCargoTypeMap.get(orderDto.getCargoType()));//设置货物类型的名字
            orderDto.setOrderStatusName(ordOrder.getOrderStatus().getName());//设置订单状态的名字
            if (ordOrder.getPayStatus() != null) {
                orderDto.setPayStatusName(ordOrder.getPayStatus().getName());//设置订单支付状态的名字
            }
            orderDto.setProductName(productMap.get(orderDto.getProductUid()));//设置产品的名字
            orderDto.setCusUserName(cusUserMap.get(orderDto.getCusUserId()));
            orderDto.setCustomerName(customerMap.get(orderDto.getCustomerId()));
            String key = ordOrder.getOrderNo() + "_" + ordOrder.getOrderStatus().getCode();
            CusCustomerOrderMessageDto messageDto = messageDtoMap.get(key);
            if (!ObjectUtils.isEmpty(messageDto)) {
                for (CustomerMessageDto customerMessageDto : messageDto.getCustomerMessageDtoList()) {
                    if ("sms".equalsIgnoreCase(customerMessageDto.getMessageType())) {
                        orderDto.setSmsStatus(customerMessageDto.getMessageStatus().name());
                    } else if ("email".equalsIgnoreCase(customerMessageDto.getMessageType())) {
                        orderDto.setEmailStatus(customerMessageDto.getMessageStatus().name());
                    }
                }
            }
            //设置城市的名字
            this.processAddress(orderDto, orderAddressMap.get(ordOrder.getOrderNo()), 2);
            ordOrderDtoList.add(orderDto);
        }
        //3、返回数据
        return new QResultDto(ordOrderDtoList, pd.getPagination());
    }

    @Override
    public QResultDto findSearchDtoByParam(QueryParams params) {
        ParamData pd = convertQueryParams(params);
        //1、根据条件查询相应的运单编号
        List<OrdOrder> ordOrderList = dao.findForList(getSqlName("searchOrderListPage"), pd, OrdOrder.class);
        Map<String, String> sysDictCargoTypeMap = dictService.findMapByCatalog(CommCodes.SYS_DICT_BIZ_CARGO_TYPE);
        //2、根据上面查询出来的信息拼装要返回给前端的dto集合信息（ordOrderDtoList）
        List<OrdOrderDto> ordOrderDtoList = new ArrayList<>();//存放拼装好的orderDto信息
        List<String> productUidList = new ArrayList<>();
        List<String> orderNoList = new ArrayList<>();
        List<Integer> cusUserIdList = new ArrayList<>();
        List<Integer> customerIdList = new ArrayList<>();
        for (OrdOrder ordOrder : ordOrderList) {
            productUidList.add(ordOrder.getProductUid());
            orderNoList.add(ordOrder.getOrderNo());
            cusUserIdList.add(ordOrder.getCusUserId());
            customerIdList.add(ordOrder.getCustomerId());
        }
        productUidList = CollectionUtils.removeDuplication(productUidList);
        orderNoList = CollectionUtils.removeDuplication(orderNoList);
        cusUserIdList = CollectionUtils.removeDuplication(cusUserIdList);
        customerIdList = CollectionUtils.removeDuplication(customerIdList);
        List<OrdOrderAddress> orderAddressList = orderAddressService.findByOrderNos(orderNoList);
        //获取地址信息
        Map<String, OrdOrderAddress> orderAddressMap = new HashMap<>();
        orderAddressList.forEach(orderAddress -> orderAddressMap.put(orderAddress.getOrderNo(), orderAddress));
        //获取产品的信息
        List<Product> productList = productService.findShortActivedByUids(productUidList);
        Map<String, String> productMap = new HashMap<>();
        productList.forEach(product -> productMap.put(product.getUid(), product.getName()));
        //获取客户的信息
        List<CusCustomer> customerList = customerService.findShortByIds(customerIdList);
        Map<Integer, String> customerMap = new HashMap<>();
        customerList.forEach(cusCustomer -> customerMap.put(cusCustomer.getId(), cusCustomer.getUserName()));
        //获取用户的信息
        List<CusUser> cusUsers = customerUserService.findShortByIds(cusUserIdList);
        Map<Integer, String> cusUserMap = new HashMap<>();
        cusUsers.forEach(cusUser -> cusUserMap.put(cusUser.getId(), cusUser.getUserName()));
        for (OrdOrder ordOrder : ordOrderList) {//向产品订单中设置子订单信息与商品明细信息
            //2.1、将ordOrder对象转成ordOrderDto对象
            OrdOrderDto orderDto = new OrdOrderDto();
            EntityUtils.copyPropertiesIgnoreNull(ordOrder, orderDto);
            orderDto.setCargoTypeName(sysDictCargoTypeMap.get(orderDto.getCargoType()));//设置货物类型的名字
            orderDto.setOrderStatusName(ordOrder.getOrderStatus().getName());//设置订单状态的名字
            orderDto.setProductName(productMap.get(orderDto.getProductUid()));//设置产品的名字
            orderDto.setCusUserName(cusUserMap.get(orderDto.getCusUserId()));
            orderDto.setCustomerName(customerMap.get(orderDto.getCustomerId()));
            //设置城市的名字
            this.processAddress(orderDto, orderAddressMap.get(ordOrder.getOrderNo()), 2);
            ordOrderDtoList.add(orderDto);
        }
        //3、返回数据
        return new QResultDto(ordOrderDtoList, pd.getPagination());
    }


    @Override
    public Map<String, List<OrdOrderTrackingShowDto>> findTrackByWaybillNo(List<Integer> rankList, String waybillNo) {

        return orderTrackingService.findByWaybillNo(rankList, waybillNo);
    }

    @Override
    public List<CommonModel> findServiceByOrderNo(String orderNo) {
        //1、获取订单
        OrdOrder ordOrder = findByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(ordOrder)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要查询的订单不存在");
        }
        //2、得到当前订单选择的可选服务
        List<String> additionalServiceUidList = orderAdditionalService.findServiceUidByOrderNo(orderNo);
        //3、、得到当前产品的所有的服务列表，这里需要orderNo是因为根据计费时间的不同，获取的数据可能不一致
        List<ProductServiceRel> productServiceRelList = this.getProductServiceRelsByProductUid(ordOrder.getProductUid(), ordOrder.getCreateTime());
        if (CollectionUtils.isEmpty(productServiceRelList)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "未找到产品对应的服务");
        }

        //4、得到订单中要选择的服务
        List<String> serviceUidList = new ArrayList<>();
        productServiceRelList.forEach(productServiceRel -> {
            //找到必选的服务和可选的服务，再综合
            if (!productServiceRel.getServiceProperty().equals(ProductServicePropertyEnum.OPTIONAL) || additionalServiceUidList.contains(productServiceRel.getServiceUid())) { //jifeixing 产品服务修改
                serviceUidList.add(productServiceRel.getServiceUid());
            }
        });
        //5、取出服务对应的名字与uid
        List<CommonModel> commonModelList = serviceService.findActivedByServiceUidList(serviceUidList);
        //5、返回数据集合
        return commonModelList;
    }

    @Override
    public List<CommonModel> getAllOrderStatus() {
        List<CommonModel> list = Lists.newArrayList();
        for (OrderStatus orderStatus : OrderStatus.values()) {
            CommonModel dto = new CommonModel(orderStatus.name(), orderStatus.getName());
            list.add(dto);
        }
        return list;
    }

    @Override
    public List<CommonModel> getOrderPayStatus() {
        List<CommonModel> list = Lists.newArrayList();
        for (PayStatus payStatus : PayStatus.values()) {
            CommonModel dto = new CommonModel(payStatus.getCode(), payStatus.getName());
            list.add(dto);
        }
        return list;
    }

    /**
     * TODO： 生成订单的计费数据，为了测试，后期需要删掉
     *
     * @param orderNo
     */
    @Override
    public void generateBillData(String orderNo) {
        OrdOrder ordOrder = findByOrderNo(orderNo);
        if (null == ordOrder) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单号不存在");
        }
        // 将订单状态改为已受理
        this.updateOrderStatusToAccept(Arrays.asList(ordOrder));

    }


    /**
     * 根据orderNos查询相应的运单信息
     *
     * @param orderNos 运单集合
     * @return 订单集合
     */
    @Override
    public List<OrdOrder> findByOrderNos(List<String> orderNos) {
        List<OrdOrder> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderNos)) {
            ParamData pd = new ParamData();
            pd.put("orderNos", orderNos);
            list = dao.findForList(getSqlName("findByOrderNos"), pd, OrdOrder.class);
        }
        return list;
    }

    @Override
    public OrdOrder findByWaybillNo(String waybillNo) {
        OrdOrder ordOrder = null;
        if (!StringUtils.isEmpty(waybillNo)) {
            List<OrdOrder> ordOrderList = this.findByWaybillNos(Arrays.asList(waybillNo));
            if (!CollectionUtils.isEmpty(ordOrderList)) {
                ordOrder = ordOrderList.get(0);
            }
        }
        return ordOrder;
    }

    @Override
    public List<OrdOrder> findByWaybillNos(List<String> waybillNos) {
        List<OrdOrder> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(waybillNos)) {
            ParamData pd = new ParamData();
            pd.put("waybillNos", waybillNos);
            list = dao.findForList(getSqlName("findByWaybillNos"), pd, OrdOrder.class);
        }
        return list;
    }


    @Override
    public List<ServiceForOrderDto> getServiceDtos(String orderNo) {
        //1、获取订单
        OrdOrder ordOrder = findByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(ordOrder)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要查询的订单不存在");
        }

        List<OrdOrderOptionService> optionServiceList = orderServiceAssignService.findOrderServiceByOrderNo(orderNo, null);

        List<ServiceForOrderDto> forOrderDtos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(optionServiceList)) {
            for (int i = 0; i < optionServiceList.size(); i++) {
                OrdOrderOptionService optionService = optionServiceList.get(i);
                Service service = serviceService.findById(optionService.getServiceId());
                if (!ObjectUtils.isEmpty(service)) {
                    ServiceForOrderDto dto = new ServiceForOrderDto();
                    dto.setServiceUid(optionService.getServiceUid());
                    dto.setSupplierId(service.getSupplierId());
                    dto.setOrdinal(i);
                    dto.setName(service.getName());
                    forOrderDtos.add(dto);
                }

            }
        }
        /*
        //2、得到当前订单选择的可选服务
        List<String> additionalServiceUidList = orderAdditionalService.findServiceUidByOrderNo(orderNo);
        //3、、得到当前产品的所有的服务列表，这里需要orderNo是因为根据计费时间的不同，获取的数据可能不一致
        List<ProductServiceRel> productServiceRelList = this.getProductServiceRelsByProductUid(ordOrder.getProductUid(), ordOrder.getCreateTime());
        //4、得到订单中要选择的服务
        List<String> serviceUidList = new ArrayList<>();
        productServiceRelList.forEach(productServiceRel -> {
            //找到必选的服务和可选的服务，再综合
            if (!(productServiceRel.getServiceProperty() == ProductServicePropertyEnum.OPTIONAL) || additionalServiceUidList.contains(productServiceRel.getServiceUid())) { //jifeixing 产品服务修改
                serviceUidList.add(productServiceRel.getServiceUid());
            }
        });
        List<Service> list = serviceService.findActivedByUids(serviceUidList);
        List<ServiceForOrderDto> dtos = Lists.newArrayList();
        if (null != list && !list.isEmpty()) {
            for (Service s : list) {
                for (ProductServiceRel psRel : productServiceRelList) {
                    if (s.getUid().equals(psRel.getServiceUid())) {
                        ServiceForOrderDto dto = new ServiceForOrderDto();
                        dto.setServiceUid(s.getUid());
                        EntityUtils.copyPropertiesIgnoreNull(s, dto);
                        dto.setOrdinal(psRel.getOrdinal() == null ? 0 : psRel.getOrdinal());
                        dto.setServiceTypeName(psRel.getServiceTypeName());
                        dtos.add(dto);
                    }
                }
            }
            Collections.sort(dtos, new Comparator<ServiceForOrderDto>() {
                @Override
                public int compare(ServiceForOrderDto o1, ServiceForOrderDto o2) {
                    return o1.getOrdinal() - o2.getOrdinal();
                }
            });
        }*/
        return forOrderDtos;
    }


    /**
     * 1、收到物流信息之后，更新订单和子单的重量、长、宽、高等信息
     * 2、如果为收货状态，重新分派服务，更新计费重、体积重
     *
     * @param trackingSupOrder 要处理的tracking信息
     * @param order            订单信息
     */
    @Override
    public OrdTrackingResult processOrderInfoByTracking(TrackingSupOrder trackingSupOrder, OrdOrder order) {

        //2、判断是否传递长、宽、高、重量、单位等信息，来决定是否对订单与子订单相应的信息做更新
        OrdTrackingResult trackingResult = this.acceptUpdateOrderInfo(trackingSupOrder, order);

        //3、如果订单的状态改为了已收货104，则需要去计算新的计费重（根据重量和体积换算的重量）
        return trackingResult;

    }

    /**
     * 如果供应商发过来的code是309代表可以出库了，这时要去看是否有阻塞性工单，如果没有，那么向供应商发送让其出库的物流消息。
     *
     * @param trackingSupOrder 供应商传过来的消息
     * @param order            订单信息
     * @return
     */
    private boolean judgeIsBlock(TrackingSupOrder trackingSupOrder, OrdOrder order, OrderStatus orderStatus) {
        boolean isBlock = false;
        if (OrderStatus.TRANSPORT == orderStatus) {
            List<CsrWorkOrderSchema> workOrderSchemaList = workOrderSchemaService.queryBlockByOrderNo(order.getOrderNo());
            if (!CollectionUtils.isEmpty(workOrderSchemaList) || PayStatus.PAID != order.getPayStatus()) {
                OrdTrackingMessage trackingMessage = new OrdTrackingMessage();
                //设置原始物流信息的id为0，表示没有原始物流信息
                trackingMessage.setMessageTime(dao.getDbDate());
                trackingMessage.setServiceUid(trackingSupOrder.getServiceUid());
                //发阻塞发货的物流信息
                trackingMessage.setEventCode(TrackMessageToServiceEnum.MSG_BLOCK_OUTGOING.getCode());
                trackingMessage.setStatus(OrderTrackingConstants.TrackingStatus.TRACKING_STATUS_NUSYNC);
                trackingMessage.setSupplierId(trackingSupOrder.getSupplierId());
                trackingMessage.setTrackingReport(null);//TODO 等着报文定下来
                trackingMessage.setType(OrderTrackingConstants.TrackingType.TRACKING_TYPE_SYSTEM);
                trackingMessage.setWaybillNo(order.getWaybillNo());
                if (!CollectionUtils.isEmpty(workOrderSchemaList)) {
                    trackingMessage.setDescription("请不要发货，有阻塞的工单！");
                } else {
                    trackingMessage.setDescription("请不要发货，订单未完成支付！");
                }
                trackingMessageService.save(trackingMessage);
                isBlock = true;
            } else {
                //this.sendOutgoingTracking(order.getOrderNo());
            }
        }
        return isBlock;
    }


    /**
     * 继续出库的物流消息
     *
     * @param orderNo 订单号
     */
    private void sendOutgoingTracking(String orderNo) {
        OrdOrder order = this.findByOrderNo(orderNo);
        List<OrdOrderTracking> ordOrderTrackingList = orderTrackingService.findByWaybillNo(order.getWaybillNo(), "304");
        if (!CollectionUtils.isEmpty(ordOrderTrackingList)) {
            OrdOrderTracking ordOrderTracking = ordOrderTrackingList.get(ordOrderTrackingList.size() - 1);
            OrdTrackingMessage trackingMessage = new OrdTrackingMessage();
            //设置原始物流信息的id为0，表示没有原始物流信息
            trackingMessage.setMessageTime(dao.getDbDate());
            trackingMessage.setServiceUid(ordOrderTracking.getServiceUid());
            //发阻塞发货的物流信息
            trackingMessage.setEventCode(TrackMessageToServiceEnum.MSG_OUTGOING.getCode());
            trackingMessage.setStatus(OrderTrackingConstants.TrackingStatus.TRACKING_STATUS_NUSYNC);
            trackingMessage.setSupplierId(ordOrderTracking.getSupplierId());
            trackingMessage.setTrackingReport("");//TODO 等待确认要发送的内容
            trackingMessage.setType(OrderTrackingConstants.TrackingType.TRACKING_TYPE_SYSTEM);
            trackingMessage.setWaybillNo(ordOrderTracking.getWaybillNo());
            trackingMessage.setDescription(TrackMessageToServiceEnum.MSG_OUTGOING.getName());
            trackingMessageService.save(trackingMessage);
        }
    }

    /**
     * 根据物流的信息更新订单、子单的信息
     *
     * @param trackingSupOrder 供应商发的物流消息
     * @param order            订单的信息
     */
    private OrdTrackingResult acceptUpdateOrderInfo(TrackingSupOrder trackingSupOrder, OrdOrder order) {
        OrdTrackingResult trackingResult = new OrdTrackingResult();
        OrderStatus origOrderStatus = order.getOrderStatus();
        List<String> reviseStatusList = orderStatusCodeService.findReviseStatusList();

        //2、当消息为供应商发出并且消息的code包含在reviseStatusList中才操作对应订单、子单的消息
        if (reviseStatusList.contains(trackingSupOrder.getCode())) {
            OrdOrderStatusCode ordOrderStatusCode = orderStatusCodeService.getByCode(trackingSupOrder.getCode());
            OrderStatus orderStatus = ordOrderStatusCode.getOrderStatus();
            if (!ObjectUtils.isEmpty(orderStatus)) {


                //1、更新子单信息
                Map<String, OrdSubOrder> subOrderMap = subOrderService.findMapByOrderNo(order.getOrderNo());
                for (TrackingSupSubOrder trackingSupSubOrder : trackingSupOrder.getTrackingSupSubOrders()) {
                    OrdSubOrder subOrder = subOrderMap.get(trackingSupSubOrder.getSubOrderNo());
                    if (OrderStatus.RECEGOOD == orderStatus || OrderStatus.TRANSPORT == orderStatus) {
                        this.setSubOrderLwhAndWeight(trackingSupSubOrder, subOrder);
                    }
                    //设置子单的状态
                    subOrder.setOrderStatus(orderStatus);
                }
                subOrderService.batchUpdate(new ArrayList<>(subOrderMap.values()));

                //2、更新订单信息
                // 已收货时，才处理子单的信息
                //更新订单的重量、单位等信息
                if (OrderStatus.RECEGOOD == orderStatus || OrderStatus.TRANSPORT == orderStatus) {
                    if (!ObjectUtils.isEmpty(trackingSupOrder.getOrderWeight()) &&
                            !ObjectUtils.isEmpty(trackingSupOrder.getOrderWeightUnit())) {
                        order.setSupWeight(trackingSupOrder.getOrderWeight());
                        order.setSupWeightUnit(trackingSupOrder.getOrderWeightUnit().toLowerCase());
                    }
                }
                //如果订单状态为"已收货"，那么对ord_order表中的receiveCargoTime更新
                if (OrderStatus.RECEGOOD == orderStatus) {
                    order.setReceiveCargoTime(dao.getDbDate());

                }
                order.setOrderStatus(orderStatus);
                this.update(order);


                switch (orderStatus) {
                    case RECEGOOD:
                        //当已经收货后，重新分派服务，并计算费用
                        this.dealFeeCalcWeight(order.getOrderNo());
                        orderFeeService.submitBillByReceGood(order.getOrderNo());
                        break;
                    case TRANSPORT:
                        this.dealFeeCalcWeight(order.getOrderNo());
                        //当运输中时，重新分派服务，并计算费用，如果失败，那么更新订单状态为原始状态
                        boolean isOk = orderFeeService.submitBillByTransport(order.getOrderNo());
                        //当出库时失败，那么要将订单的状态更新为原来的状态。
                        if (!isOk) {
                            //更新订单状态与子订单状态，为原来的状态
                            order.setFeeCalcWeight(null);
                            order.setFeeCalcWeightUnit(null);
                            this.updateTansportStauts(order, trackingResult, origOrderStatus);
                        } else {
                            //如果本次重新分派服务，并计算费用成功后，当前是有阻塞性工单，订单未支付,也不允许出库,这时对订单的状态也不进行更改
                            if (workOrderSchemaService.isBlockByOrderNo(order.getOrderNo()) || order.getPayStatus() != PayStatus.PAID) {
                                this.updateTansportStauts(order, trackingResult, origOrderStatus);
                            }
                        }
                        break;
                }


            }
        }
        return trackingResult;
    }

    private void updateTansportStauts(OrdOrder order, OrdTrackingResult trackingResult, OrderStatus origOrderStatus) {
        order.setOrderStatus(origOrderStatus);
        order.setTransportStatus(OrderConstants.OrderTransportStatus.ORDER_TRANSPORT);
        this.update(order);
        subOrderService.updateOrderStatusByOrderNo(order.getOrderNo(), origOrderStatus);
        trackingResult.setSuccess(false);
        trackingResult.setReason(ErrorCodes.ERROR_CSR_ORDER_BLOCK.getCode());
        String message = I18nMessageHelper.getI18nMessage(ErrorCodes.ERROR_CSR_ORDER_BLOCK.getMessageKey(), null);
        trackingResult.setReasonContent(message);
    }


    /**
     * 判断是否需要向子单中设置长、宽、高、重量、及相应的单位
     *
     * @param trackingSupSubOrder
     * @param subOrder
     * @return
     */

    private void setSubOrderLwhAndWeight(TrackingSupSubOrder trackingSupSubOrder, OrdSubOrder subOrder) {
        if (!ObjectUtils.isEmpty(trackingSupSubOrder)) {
            //当长宽高和单位都有值时
            if (!ObjectUtils.isEmpty(trackingSupSubOrder.getLength())
                    && !ObjectUtils.isEmpty(trackingSupSubOrder.getWidth())
                    && !ObjectUtils.isEmpty(trackingSupSubOrder.getHeight())
                    && !ObjectUtils.isEmpty(trackingSupSubOrder.getLwhUnit())) {
                subOrder.setLwhUnit(trackingSupSubOrder.getLwhUnit().toLowerCase());
                subOrder.setLength(trackingSupSubOrder.getLength());
                subOrder.setWidth(trackingSupSubOrder.getWidth());
                subOrder.setHeight(trackingSupSubOrder.getHeight());
            }
            //当重量和单位都有值时
            if (!ObjectUtils.isEmpty(trackingSupSubOrder.getWeight())
                    && !ObjectUtils.isEmpty(trackingSupSubOrder.getWeightUnit())) {
                subOrder.setWeightUnit(trackingSupSubOrder.getWeightUnit().toLowerCase());
                subOrder.setWeight(trackingSupSubOrder.getWeight());
            }
            subOrder.setCargoNumber(trackingSupSubOrder.getCargoNumber());
        }
    }

    /**
     * 检查serviceUid，supplierId是否为订单的服务-供应商之一
     *
     * @param ordOrder
     * @param serviceUid
     * @return
     */
    @Override
    public boolean validateServiceUid(OrdOrder ordOrder, String serviceUid, Integer supplierId) {
        boolean bOk = false;
        List<ProductServiceRel> productServiceRels = this.getProductServiceRelsByProductUid(ordOrder.getProductUid(), ordOrder.getReceiveCargoTime());
        if (!CollectionUtils.isEmpty(productServiceRels)) {
            for (ProductServiceRel productServiceRel : productServiceRels) {
                if (!StringUtils.isEmpty(productServiceRel.getServiceUid()) && productServiceRel.getServiceUid().equals(serviceUid)) {
                    //供应商判断
                    if (null != supplierId && supplierId.intValue() > 0) {
                        Service service = serviceService.findByUidAndTime(serviceUid, ordOrder.getReceiveCargoTime());
                        if (!ObjectUtils.isEmpty(service) && service.getSupplierId().intValue() == supplierId.intValue()) {
                            bOk = true;
                        }
                    }
                }
            }
        }
        return bOk;
    }

    /**
     * 获取两个月内还没有计费的运单
     */
    @Override
    public List<OrdOrder> findNoCalcedWaybills(int type) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderStatus", OrderStatus.RECEGOOD);
        map.put("type", type);
        return dao.findForList(getSqlName("findNoCalcedWaybills"), map, OrdOrder.class);
    }

    /**
     * 获取两个月内还没有计费的运单
     */
    @Override
    public List<OrdOrder> findNoAssignServiceBills() {
        Map<String, Object> map = new HashMap<>();
        return dao.findForList(getSqlName("findNoAssignServiceBills"), map, OrdOrder.class);
    }

    @Override
    public List<OrdOrder> findByOrderStatus(OrderStatus orderStatus, Integer beginRow, Integer endRow) {
        List<OrdOrder> ordOrderList = new ArrayList<>();
        if (!ObjectUtils.isEmpty(orderStatus)) {
            ParamData pd = new ParamData();
            pd.put("beginRow", beginRow);
            pd.put("endRow", endRow);
            pd.put("orderStatus", orderStatus);
            ordOrderList = dao.findForList(getSqlName("findByOrderStatus"), pd, OrdOrder.class);
        }
        return ordOrderList;
    }

    @Override
    public OrdOrderCusUserDto findCusUserByOrderNo(String orderNo) {
        OrdOrderCusUserDto cusUserDto = null;
        if (StringUtils.hasLength(orderNo)) {
            cusUserDto = (OrdOrderCusUserDto) dao.findForObject(getSqlName("findCusUserByOrderNo"), orderNo);
            if (ObjectUtils.isEmpty(cusUserDto)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_WAYBILLNO_NOT_EXIST);
            }
        } else {
            throw Exceptions.bizException(ErrorCodes.ERROR_WAYBILLNO_NOT_EXIST);
        }
        return cusUserDto;
    }

    @Override
    public void updateSatus(OrdOrder oldOrder, OrdOrderStatusCode statusCode) {
        if (statusCode.getIsReviseStatus()) {
            //处理订单的状态
            //获取子订单中最慢的物流状态，
            OrderStatus minSubOrderStatus = subOrderService.getMinStatusCodeByOrderNo(oldOrder.getOrderNo());
            //比较总订单的状态和子订单中最慢的物流状态
            if (null == minSubOrderStatus) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "获取最慢的子订单状态异常！");
            }
            if (oldOrder.getOrderStatus().compareTo(minSubOrderStatus) < 0) {
                OrdOrder newOrder = new OrdOrder();
                //要更新订单的状态
                newOrder.setOrderStatus(minSubOrderStatus);
                if (newOrder.getOrderStatus().equals(OrderStatus.RECEGOOD)) {//如果订单状态为"已收货"，那么对ord_order表中的receiveCargoTime更新
                    newOrder.setReceiveCargoTime(dao.getDbDate());
                }
                newOrder.setOrderNo(oldOrder.getOrderNo());
                this.update(newOrder);
            }

        }
    }

    @Override
    public void updateOrderStatus(Map<String, OrderStatus> processOrderMap) {
        if (!CollectionUtils.isEmpty(processOrderMap)) {
            List<ParamData> pdList = getParamData(processOrderMap);
            subOrderService.updateOrderStatusByOrderNos(processOrderMap);
            dao.batchUpdate(getSqlName("updateOrderStatus"), pdList);
        }
    }

    private List<ParamData> getParamData(Map<String, OrderStatus> processOrderMap) {
        List<ParamData> pdList = new ArrayList<>();
        processOrderMap.forEach((orderNo, orderStatus) -> {
            ParamData pd = new ParamData();
            pd.put("orderNo", orderNo);
            pd.put("orderStatus", orderStatus);
            pdList.add(pd);
        });
        return pdList;
    }

    /**
     * 批量把订单从草稿状态改成已提交状态，如果是自动受理的产品，应直接变成已受理状态
     *
     * @param orderNos 订单号的集合
     */

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateCommitedByOrderNos(List<String> orderNos) {
        orderNos = CollectionUtils.removeDuplication(orderNos);


        Map<String, OrderStatus> map = new HashMap<>();
        List<Integer> orderIdList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(orderNos)) {
            List<OrdOrder> orderList = this.findByOrderNos(orderNos);
            if (!CollectionUtils.isEmpty(orderList) && orderNos.size() != orderList.size()) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "存在异常订单号，请核查！");
            }

            //存放产品的uid、账号id集合、/账户id集合
            List<String> productUidList = new ArrayList<>();
            List<Integer> cusUserIdList = new ArrayList<>();
            List<Integer> cusIdList = new ArrayList<>();
            for (OrdOrder order : orderList) {

                SerialNoManagement serialNoManagement = this.handleWaybillNo(order.getOrderNo(), order.getProductUid(), order.getCustomerId(), 0l);
                order.setWaybillNo(serialNoManagement.getSerialNumber());
                this.tryUpdateOrder(order, true, serialNoManagement.getId());
                subOrderService.saveSubOrders(order.getOrderNo(), order.getWaybillNo(), order.getPackageNum(), order.getOrderStatus());

                productUidList.add(order.getProductUid());
                cusUserIdList.add(order.getCusUserId());
                cusIdList.add(order.getCustomerId());
            }

            List<Product> productList = productService.findShortActivedByUids(productUidList);//取得产品的列表
            Map<String, Product> productMap = EntityUtils.getStringKeyMapFromBeans(productList, "uid");

            List<CusCustomer> customerList = customerService.findShortByIds(cusIdList);
            Map<Integer, CusCustomer> customerMap = EntityUtils.getIntKeyMapFromBeans(customerList, "id");

            List<CusUser> cusUserList = customerUserService.findShortByIds(cusUserIdList);//取得客户的列表
            Map<Integer, CusUser> cusUserMap = EntityUtils.getIntKeyMapFromBeans(cusUserList, "id");


            List<String> cashWayBillNos = new ArrayList<String>();
            List<OrdOrder> autoOrderList = new ArrayList<>();
            for (OrdOrder ordOrder : orderList) {

                int acceptType = productService.getProductAcceptType(ordOrder.getProductUid());
                if (CommCodes.PRODUCT_ACCETP_TYPE_MANUAL == acceptType) {
                    String orderNo = ordOrder.getOrderNo();
                    //判断订单的状态
                    if (ordOrder.getOrderStatus() != OrderStatus.DRAFT) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "运单号：" + ordOrder.getOrderNo() + "非草稿状态！");
                    }

                    //校验产品、客户的账户、客户的账号的有效性
                    this.judgeProductAndCustomer(productMap, customerMap, cusUserMap, ordOrder);
                    //更新订单的状态
                    map.put(orderNo, OrderStatus.COMMITED);
                    orderIdList.add(ordOrder.getId());
                    //取出子订单号并添加物流信息
                    List<String> subOrderNos = subOrderService.getSubOrdNos(orderNo);
                    this.processTrackings(OrderStatus.COMMITED, orderNo, ordOrder.getWaybillNo(), subOrderNos);

                } else {
                    autoOrderList.add(ordOrder);
                }
            }
            //批量更新订单的状态
            this.updateOrderStatus(map);

            if(!CollectionUtils.isEmpty(map)){
                map.forEach((key,value)->{
                    orderFeeService.submitBillByAccept(key);
                });
            }



            //对于自动受理的产品，在更新成提交状态时，要直接变成已受理
            if (!CollectionUtils.isEmpty(autoOrderList)) {
                updateOrderStatusToAccept(autoOrderList);
            }

            // 增加订单的操作日志详情 add 2017-10
            Integer accountId = PrincipalUtils.getAccountId();
            Integer domainId = PrincipalUtils.getDomainId();
            operationLogService.saveOrdOperLogForBatchAcceptOrSubmit(orderIdList, UserActions.UPDATE, accountId, domainId, OrdOperationLogEnum.SUBMIT_ORDER);
        }
    }

    public void updateOrderNoByOrderNo(String oldOrderNo, String newOrderNo) {
        if (StringUtils.isEmpty(oldOrderNo) || StringUtils.isEmpty(newOrderNo)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单异常");
        }
        ParamData pd = new ParamData();
        pd.put("newOrderNo", newOrderNo);
        pd.put("oldOrderNo", oldOrderNo);
        dao.update(getSqlName("updateOrderNoByOrderNo"), pd);
    }

    /**
     * 根据订单号的集合对已提交的订单批量受理
     *
     * @param orderNos 订单号集合
     */
    @Override
    public void updateAcceptByOrderNos(List<String> orderNos) {
        if (!CollectionUtils.isEmpty(orderNos)) {
            List<OrdOrder> ordOrderList = this.findByOrderNos(orderNos);
            Map<String, OrdOrder> ordOrderMap = EntityUtils.getStringKeyMapFromBeans(ordOrderList, "orderNo");

            for (String orderNo : orderNos) {
                OrdOrder ordOrder = ordOrderMap.get(orderNo);
                if (ObjectUtils.isEmpty(ordOrder)) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "单号：" + orderNo + "不存在！");
                }
                if (ordOrder.getOrderStatus() != OrderStatus.COMMITED) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "单号：" + ordOrder.getWaybillNo() + "非已提交状态！");
                }
            }
            this.updateOrderStatusToAccept(ordOrderList);
        }
    }

    /**
     * 获取现结客户未付款的订单编号集合
     *
     * @param ordOrderList
     * @return List<String>
     */
    private List<String> getCashCusNoPayOrders(List<OrdOrder> ordOrderList) {
        //过滤出结算方式为现结的,未支付的订单
        List<String> noPaidWayBillNoList = new ArrayList<String>();
        for (OrdOrder order : ordOrderList) {
            if (null != order.getSettlementTypeId() && CommCodes.CASH_PAID == order.getSettlementTypeId() && order.getPayStatus().getCode().equals(PayStatus.UNPAID.getCode())) {
                noPaidWayBillNoList.add(order.getWaybillNo());
            }
        }
        return noPaidWayBillNoList;
    }

    @Override
    public void updateOrderStatus(String orderNo, OrderStatus orderStatus) {
        if (StringUtils.hasLength(orderNo) && !ObjectUtils.isEmpty(orderStatus)) {
            Map<String, OrderStatus> orderStatusMap = new HashMap<>();
            orderStatusMap.put(orderNo, orderStatus);
            this.updateOrderStatus(orderStatusMap);
        }
    }

    @Override
    public OrdOrder findByExternalNoAndCustomerId(String externalNo, int customerId, int id) {
        ParamData pd = new ParamData();
        pd.put("externalNo", externalNo);
        pd.put("customerId", customerId);
        pd.put("id", id);
        return (OrdOrder) dao.findForObject(getSqlName("findByExternalNoAndCustomerId"), pd);
    }


    @Override
    public void sendOrderStatusMessage(List<String> orders) {
        List<OrdOrder> ordOrders = findByOrderNos(orders);
        MessageTemplate smsTemplate = messageTemplateService.findByTemplateTypeAndRefParendId(CustomerNoticeMessageTypeEnum.SMS.getCode(), 1);
        MessageTemplate emailTemplate = messageTemplateService.findByTemplateTypeAndRefParendId(CustomerNoticeMessageTypeEnum.EMAIL.getCode(), 1);
        if (ordOrders != null && ordOrders.size() > 0) {
            for (OrdOrder ordOrder : ordOrders) {
                int customerId = ordOrder.getCustomerId();
                if (customerId != 0) {
                    OrderStatus orderStatus = ordOrder.getOrderStatus();
                    int refId = 0;
                    switch (orderStatus) {
                        case COMMITED:
                            refId = 2;
                            break;
                        case ACCEPT:
                            refId = 3;
                            break;
                        case RECEGOOD:
                            refId = 4;
                            break;
                        case TRANSPORT:
                            refId = 5;
                            break;
                        case DISPACTCHING:
                            refId = 6;
                            break;
                        case RECEIVED:
                            refId = 7;
                            break;
                        default:
                            refId = 0;
                    }
                    if (refId != 0) {
                        CusUser cusUser = customerUserService.findById(ordOrder.getCusUserId());
                        if (cusUser != null && cusUser.getRefCustomerId() != 0) {
                            CustomerMessageRel customerMessageRel = customerMessageRelService.queryByCustomerIdAndRefId(customerId, refId);
                            if (customerMessageRel != null && !StringUtils.isEmpty(customerMessageRel.getSendType())) {
                                List<String> sendTypes = Arrays.asList(customerMessageRel.getSendType().split(","));
                                CusCustomerOrderMessage cusCustomerOrderMessage = new CusCustomerOrderMessage();
                                cusCustomerOrderMessage.setBusinessType("1");
                                cusCustomerOrderMessage.setCustomerId(ordOrder.getCustomerId());
                                cusCustomerOrderMessage.setCusUserId(ordOrder.getCusUserId());
                                cusCustomerOrderMessage.setOrderStatus(ordOrder.getOrderStatus().getCode());
                                cusCustomerOrderMessage.setOrderNo(ordOrder.getOrderNo());
                                int currentOrderSendTimes = cusCustomerOrderMessageService.querySendTimes("1", ordOrder.getOrderNo(), ordOrder.getOrderStatus().getCode());
                                currentOrderSendTimes++;
                                cusCustomerOrderMessage.setSendTimes(currentOrderSendTimes);
                                for (String sendtype : sendTypes) {
                                    if (CustomerNoticeMessageTypeEnum.EMAIL.getCode().equalsIgnoreCase(sendtype)) {
                                        Map<String, Object> emailBodyMap = new HashMap<>();
                                        emailBodyMap.put("orderNo", ordOrder.getOrderNo());
                                        emailBodyMap.put("orderStatus", orderStatus.getName());
                                        emailBodyMap.put("phone", phone);
                                        String emailBody = JsonUtils.toJSONString(emailBodyMap);
                                        int id = (int) sysMailService.createMail("sys.logistics.master@hna.com", new String[]{cusUser.getEmail()}, "订单状态通知", emailBody, emailTemplate.getTemplateUrl());
                                        cusCustomerOrderMessage.setRefMessageId(id);
                                        cusCustomerOrderMessage.setMessageType(sendtype);
                                        cusCustomerOrderMessageService.save(cusCustomerOrderMessage);
                                    }
                                    if (CustomerNoticeMessageTypeEnum.SMS.getCode().equalsIgnoreCase(sendtype)) {
                                        Map<String, Object> smsBodyMap = new HashMap<>();
                                        smsBodyMap.put("orderNo", ordOrder.getOrderNo());
                                        smsBodyMap.put("orderStatus", orderStatus.getName());
                                        smsBodyMap.put("phone", phone);
                                        String smsBody = JsonUtils.toJSONString(smsBodyMap);
                                        cusCustomerOrderMessage.setMessageType(sendtype);
                                        int id = sysSmsService.createSMS(cusUser.getMobilePhone(), smsBody, smsTemplate.getTemplateUrl());
                                        cusCustomerOrderMessage.setRefMessageId(id);
                                        cusCustomerOrderMessage.setMessageType(sendtype);
                                        cusCustomerOrderMessageService.save(cusCustomerOrderMessage);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public OrderMessageList getOrderMessageList(List<String> orders) {
        List<OrdOrder> ordOrders = findByOrderNos(orders);
        OrderMessageList orderMessageList = new OrderMessageList();
        if (ordOrders != null && ordOrders.size() > 0) {
            for (OrdOrder ordOrder : ordOrders) {
                int customerId = ordOrder.getCustomerId();
                if (customerId != 0) {
                    OrderStatus orderStatus = ordOrder.getOrderStatus();
                    int refId = 0;
                    switch (orderStatus) {
                        case COMMITED:
                            refId = 2;
                            break;
                        case ACCEPT:
                            refId = 3;
                            break;
                        case RECEGOOD:
                            refId = 4;
                            break;
                        case TRANSPORT:
                            refId = 5;
                            break;
                        case DISPACTCHING:
                            refId = 6;
                            break;
                        case RECEIVED:
                            refId = 7;
                            break;
                        default:
                            refId = 0;
                    }
                    if (refId != 0) {
                        CustomerMessageRel customerMessageRel = customerMessageRelService.queryByCustomerIdAndRefId(customerId, refId);
                        if (customerMessageRel != null) {
                            orderMessageList.getSendOrders().add(ordOrder.getOrderNo());
                        } else {
                            orderMessageList.getUnSendOrders().add(ordOrder.getOrderNo());
                        }
                    } else {
                        orderMessageList.getUnSendOrders().add(ordOrder.getOrderNo());
                    }
                }
            }
        }
        return orderMessageList;
    }

    /**
     * 将指定的订单更新为已受理
     * 将订单状态变为已受理
     * 1. 产生服务商-供应商下单
     * 2. 发出第一条揽货的物流tracking消息
     * 3. 更新订单和子订单的状态为已受理
     *
     * @param orderList 要处理的订单的集合
     */

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateOrderStatusToAccept(List<OrdOrder> orderList) {
        if (!CollectionUtils.isEmpty(orderList)) {
            //手动受理的订单信息
            List<String> manualOrderNoList = new ArrayList<>();//存放手动受理的订单编号信息
            List<OrdOrder> manualOrderList = new ArrayList<>();//存放手动受理的订单集合，这部分数据需要校验

            //全部的订单orderNo信息
            List<String> allOrderNoList = new ArrayList<>();//自动受理产品的订单号集合,自动受理的产品不需要做校验
            //存放订单的id信息
            List<Integer> orderIds = new ArrayList<>();//存放订单id信息

            List<String> productUidList = new ArrayList<>();//存放产品的uid
            List<Integer> cusUserIdList = new ArrayList<>();//账号id集合
            List<Integer> cusIdList = new ArrayList<>();//账户id集合

            orderList.forEach(order -> {

                if (OrderStatus.ACCEPT.compareTo(order.getOrderStatus()) < 0) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "运单号:" + order.getWaybillNo() + "不能受理！");
                }//将订单的状态更为已受理
                order.setOrderStatus(OrderStatus.ACCEPT);
                int acceptType = productService.getProductAcceptType(order.getProductUid());
                if (CommCodes.PRODUCT_ACCETP_TYPE_AUTO != acceptType) {
                    manualOrderList.add(order);
                    manualOrderNoList.add(order.getOrderNo());
                    productUidList.add(order.getProductUid());
                    cusUserIdList.add(order.getCusUserId());
                    cusIdList.add(order.getCustomerId());
                }
                allOrderNoList.add(order.getOrderNo());
                orderIds.add(order.getId());
            });

            if (!CollectionUtils.isEmpty(manualOrderNoList)) {
                //获取产品的map信息
                List<Product> productList = productService.findShortActivedByUids(productUidList);//取得产品的列表
                Map<String, Product> productMap = EntityUtils.getStringKeyMapFromBeans(productList, "uid");
                //获取客户的账户map信息
                List<CusCustomer> customerList = customerService.findShortByIds(cusIdList);
                Map<Integer, CusCustomer> customerMap = EntityUtils.getIntKeyMapFromBeans(customerList, "id");
                //获取客户的账号map信息
                List<CusUser> cusUserList = customerUserService.findShortByIds(cusUserIdList);//取得客户的列表
                Map<Integer, CusUser> cusUserMap = EntityUtils.getIntKeyMapFromBeans(cusUserList, "id");

                for (OrdOrder ordOrder : manualOrderList) {
                    judgeProductAndCustomer(productMap, customerMap, cusUserMap, ordOrder);
                }
            }

            //获取子订单的map数据
            Map<String, List<String>> subOrderNoList = subOrderService.findMapByOrderNos(allOrderNoList);//获取子订单集合
            //存放物流信息
            List<OrdOrderTracking> orderTrackingList = new ArrayList<>();//存放物流信息
            //批量添加子订单的物流信息
            for (OrdOrder order : orderList) {
                //2、添加子订单的物流消息
                List<String> subOrderNos = subOrderNoList.get(order.getOrderNo());
                List<OrdOrderTracking> subOrderTracking;
                //自动受理
                if (!manualOrderNoList.contains(order.getOrderNo())) {
                    subOrderTracking = subOrderService.batchAddSubTrackings(order.getOrderNo(), order.getWaybillNo(), order.getOrderStatus(), subOrderNos);
                } else {//手动受理产品
                    subOrderTracking = subOrderService.processOrderTracking(order.getOrderNo(), order.getWaybillNo(), subOrderNos, Arrays.asList(CommCodes.TRACKING_CODE_WAIT_RECEGOOD));
                }
                orderTrackingList.addAll(subOrderTracking);
            }

            //批量保存物流信息
            orderTrackingService.batchSave(orderTrackingList);//物流信息

            //批量把订单的状态改成已受理
            this.updateOrderStatus(allOrderNoList, OrderStatus.ACCEPT);//更新订单状态

            // 增加订单的操作日志, add  2017-10
            Integer accountId = PrincipalUtils.getAccountId();
            Integer domainId = PrincipalUtils.getDomainId();
            operationLogService.saveOrdOperLogForBatchAcceptOrSubmit(orderIds, UserActions.UPDATE, accountId, domainId, OrdOperationLogEnum.ACCEPT_ORDER);

            //服务分派，失败则创建工单
            for (OrdOrder ordOrder : orderList) {
                orderFeeService.submitBillByAccept(ordOrder.getOrderNo());
            }
        }

    }

    /**
     * 判断产品、客户的账户、客户的账号的有效性
     *
     * @param productMap  产品的map
     * @param customerMap 客户账户的map
     * @param cusUserMap  客户账号的map
     * @param ordOrder    订单集合
     */
    private void judgeProductAndCustomer(Map<String, Product> productMap, Map<Integer, CusCustomer> customerMap, Map<Integer, CusUser> cusUserMap, OrdOrder ordOrder) {
        //校验产品的有效性
        Product product = productMap.get(ordOrder.getProductUid());
        if (ObjectUtils.isEmpty(product) || product.getIsOnline() == false) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单号：" + ordOrder.getOrderNo() + "，对应的产品未上线！");
        }
        //校验客户账户的有效性（如果账户被锁定，那么所有的子账号也不能使用）
        CusCustomer customer = customerMap.get(ordOrder.getCustomerId());
        if (ObjectUtils.isEmpty(customer) || (!ObjectUtils.isEmpty(customer) && (customer.getDeleted() || customer.getLocked()))) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单号：" + ordOrder.getOrderNo() + "，客户的账户异常！");
        }
        //校验客户账号的有效性
        CusUser cusUser = cusUserMap.get(ordOrder.getCusUserId());
        if (ObjectUtils.isEmpty(cusUser) || (!ObjectUtils.isEmpty(cusUser) && (cusUser.getIsDeleted() || cusUser.getIsLocked()))) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单号：" + ordOrder.getOrderNo() + "，客户的账号异常！");
        }
    }

    @Override
    public List<ProductServiceRel> getProductServiceRelsByProductUid(String productUid, Date date) {
        if (null == productUid) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "productUid不能为空！");
        }
        return productServiceRelService.findServicesByUidAndDate(productUid, date);

    }

    /**
     * 保存订单下面别的属性，例如：子订单、可选服务、货物信息
     *
     * @param orderDto 订单dto信息
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    void processOther(OrdOrderDto orderDto) {
        //2、保存订单对应的货物信息
        orderCargoService.saveCargoDtos(orderDto.getOrderNo(), orderDto.getProductUid(), orderDto.getOrderCargoDtos());
        //3、保存可选服务
        this.processOptional(orderDto);
    }


    private void save(OrdOrder order) {
        if (!ObjectUtils.isEmpty(order)) {
            dao.save(getSqlName("insertSelective"), order);
        }
    }


    /**
     * 保存可选服务
     *
     * @param orderDto
     */
    private void processOptional(OrdOrderDto orderDto) {
        List<OrdOrderAdditionalDto> orderAdditionalDtoList = orderDto.getOrderAdditionalDtos();
        List<OrdOrderAdditional> ordOrderAdditionalList = new ArrayList<>();
        for (OrdOrderAdditionalDto item : orderAdditionalDtoList) {
            OrdOrderAdditional orderAdditional = new OrdOrderAdditional();
            EntityUtils.copyPropertiesIgnoreNull(item, orderAdditional);
            orderAdditional.setOrderNo(orderDto.getOrderNo());
            orderAdditional.setServiceTypeCode(item.getServiceTypeCode());
            ordOrderAdditionalList.add(orderAdditional);
        }
        orderAdditionalService.batchSave(ordOrderAdditionalList);

    }

    /**
     * 处理地址,将dto中的地址信息处理成entry中的地址信息
     *
     * @param dto          dto中的订单地址信息
     * @param orderAddress entry中的订单地址信息
     */
    private void setAddress(OrdOrderDto dto, OrdOrderAddress orderAddress) {
        //设置地址的name信息
        areaService.setAddressModel(dto.getFromAddress());
        areaService.setAddressModel(dto.getToAddress());
        areaService.setAddressModel(dto.getFetchAddress());
        EntityUtils.copyPropertiesIgnoreNull(dto, orderAddress);//电话号码会通过对拷复制过去
        this.fillFromAddress(dto, orderAddress);//向dto填充发件人地址
        this.fillToAddress(dto, orderAddress);//向dto填充收件人地址
        this.fillFetchAddress(dto, orderAddress);//向dto填充揽收地址
    }

    /**
     * 将从数据库中查询出来的地址填充到dto中
     *
     * @param dto          返回给前端的dto数据
     * @param orderAddress 订单的地址信息
     */
    private void fillToAddress(OrdOrderDto dto, OrdOrderAddress orderAddress) {
        //设置收件人地址
        if (dto.getToAddress().getTransportType() <= 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "收件人地址类型异常!");
        }

        if (StringUtils.isEmpty(dto.getToPhone()) && StringUtils.isEmpty(dto.getToTelephone())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "收件人固定电话或手机号码不能全为空!");
        }
        orderAddress.setToTransportType(dto.getToAddress().getTransportType());
        if (dto.getToAddress().getTransportType() == CommCodes.TRANSPORT_AIR || dto.getToAddress().getTransportType() == CommCodes.TRANSPORT_SEA) {
            if (dto.getToAddress().getTransportId() <= 0) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "收件人运输工具类型异常");
            }
        }
        if ((dto.getToAddress().getTransportType() == CommCodes.TRANSPORT_AIR
                || dto.getToAddress().getTransportType() == CommCodes.TRANSPORT_SEA)
                && "CN".equalsIgnoreCase(dto.getToAddress().getCountryCode())) {
            AreaDto areaDto = areaService.findByAreaId(dto.getToAddress().getCityId(), dto.getToAddress().getCountryCode());
            if (!ObjectUtils.isEmpty(areaDto)) {
                dto.getToAddress().setProvinceId(areaDto.getParentId());
            }
        }
        orderAddress.setToTransportId(dto.getToAddress().getTransportId());
        orderAddress.setToTransportType(dto.getToAddress().getTransportType());
        orderAddress.setToCountry(dto.getToAddress().getCountryCode());
        orderAddress.setToProvince(dto.getToAddress().getProvinceId());
        orderAddress.setToCity(dto.getToAddress().getCityId());
        orderAddress.setToDistrict(dto.getToAddress().getDistrictId());
        orderAddress.setToStreet(dto.getToAddress().getStreetId());
        orderAddress.setToAddress(dto.getToAddress().getAddress());
        orderAddress.setToPostcode(dto.getToAddress().getPostcode());
        orderAddress.setToEmail(dto.getToAddress().getEmail());
        String addressDetail = this.processAddressDetail(dto.getToName(), orderAddress.getToTelephone(), dto.getToAddress(), dto.getToPhone());
        orderAddress.setToDetail(addressDetail);
    }

    /**
     * 将从数据库中查询出来的地址填充到dto中
     *
     * @param dto          返回给前端的dto数据
     * @param orderAddress 订单的地址信息
     */
    private void fillFetchAddress(OrdOrderDto dto, OrdOrderAddress orderAddress) {
        boolean bOk = this.isExistOptionService(dto.getOrderAdditionalDtos(), dto.getProductUid());

        if (bOk) {//如果要保存的订单中有揽收服务，那么才处理揽收地址
            if (ObjectUtils.isEmpty(dto.getFetchAddress())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "揽货联系人不能为空!");
            }
            dto.getFetchAddress().setTransportType(11);
            if (StringUtils.isEmpty(dto.getFetchPhone()) && StringUtils.isEmpty(dto.getFetchTelephone())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "揽货联系人固定电话或手机号码不能全为空!");
            }
            if (dto.getFetchAddress().getTransportType() <= 0) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "揽货联系人地址类型异常");
            }
            if (dto.getFetchAddress().getTransportType() == CommCodes.TRANSPORT_AIR || dto.getFetchAddress().getTransportType() == CommCodes.TRANSPORT_SEA) {
                if (dto.getFetchAddress().getTransportId() <= 0) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "揽货联系人运输工具类型异常");
                }
            }
            if ((dto.getFetchAddress().getTransportType() == CommCodes.TRANSPORT_AIR
                    || dto.getFetchAddress().getTransportType() == CommCodes.TRANSPORT_SEA)
                    && "CN".equalsIgnoreCase(dto.getFetchAddress().getCountryCode())) {
                AreaDto areaDto = areaService.findByAreaId(dto.getFetchAddress().getCityId(), dto.getFetchAddress().getCountryCode());
                if (!ObjectUtils.isEmpty(areaDto)) {
                    dto.getFetchAddress().setProvinceId(areaDto.getParentId());
                }
            }
            //如果地址非陆运地址，那么要设置运输类型的id
            orderAddress.setFetchTransportId(dto.getFetchAddress().getTransportId());
            orderAddress.setFetchTransportType(dto.getFetchAddress().getTransportType());
            orderAddress.setFetchCountry(dto.getFetchAddress().getCountryCode());
            orderAddress.setFetchProvince(dto.getFetchAddress().getProvinceId());
            orderAddress.setFetchCity(dto.getFetchAddress().getCityId());
            orderAddress.setFetchDistrict(dto.getFetchAddress().getDistrictId());
            orderAddress.setFetchStreet(dto.getFetchAddress().getStreetId());
            orderAddress.setFetchAddress(dto.getFetchAddress().getAddress());
            orderAddress.setFetchPostcode(dto.getFetchAddress().getPostcode());
            orderAddress.setFetchEmail(dto.getFetchAddress().getEmail());
            String addressDetail = this.processAddressDetail(dto.getFetchName(), orderAddress.getFetchTelephone(), dto.getFetchAddress(), dto.getFetchPhone());
            orderAddress.setFetchDetail(addressDetail);
        } else {
            //如果地址非陆运地址，那么要设置运输类型的id
            orderAddress.setFetchName(null);
            orderAddress.setFetchPhone(null);
            orderAddress.setFetchTransportId(null);
            orderAddress.setFetchTransportType(null);
            orderAddress.setFetchCountry(null);
            orderAddress.setFetchProvince(null);
            orderAddress.setFetchCity(null);
            orderAddress.setFetchDistrict(null);
            orderAddress.setFetchStreet(null);
            orderAddress.setFetchAddress(null);
            orderAddress.setFetchPostcode(null);
            orderAddress.setFetchDetail(null);
        }
    }

    /**
     * 判断可选服务在当前订单中是否存在
     *
     * @param orderAdditionalDtos 订单选择的可选服务
     * @param productUid          产品的uid
     * @return 包含可选服务：true  不包含可选服务：false
     */
    @Override
    public boolean isExistOptionService(List<OrdOrderAdditionalDto> orderAdditionalDtos, String productUid) {
        List<String> optionalServiceTypes = this.getOptionalServiceTypes(orderAdditionalDtos);

        //提货人有效性校验 如果产品需要提货地址，那么提货地址就一定要传//
        //查询产品的服务里面是否有提货服务。
        ProductReceiveInfoDto receiveInfoDto = productService.findProductReceiveInfoByUid(productUid);
        //主服务和必选服务中是否有提货服务.
        boolean bOk = receiveInfoDto.isProductReceive();

        if (!bOk && !CollectionUtils.isEmpty(optionalServiceTypes)) {
            List<ServiceTypeReceiveInfo> receiveTypeInfoList = receiveInfoDto.getServiceTypeReceiveInfo();
            for (ServiceTypeReceiveInfo serviceTypeReceiveInfo : receiveTypeInfoList) {
                if (serviceTypeReceiveInfo.isServiceReceive() && optionalServiceTypes.contains(serviceTypeReceiveInfo.getServiceTypeCode())) {
                    bOk = true;
                    break;
                }
            }
        }
        return bOk;
    }

    @Override
    public OrdOrderDto findDtoByWaybillNo(String waybillNo) {
        OrdOrderDto ordOrderDto = null;
        String orderNo = findOrderNoByWaybillNo(waybillNo);
        if (!StringUtils.isEmpty(orderNo)) {
            ordOrderDto = this.findDtoByOrderNo(orderNo);
        }
        return ordOrderDto;
    }


    private List<String> getOptionalServiceTypes(List<OrdOrderAdditionalDto> orderAdditionalDtos) {
        List<String> optionalServiceTypeCodeList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderAdditionalDtos)) {
            orderAdditionalDtos.forEach(ordOrderAdditionalDto -> optionalServiceTypeCodeList.add(ordOrderAdditionalDto.getServiceTypeCode()));
        }
        return optionalServiceTypeCodeList;
    }

    /**
     * 将从数据库中查询出来的地址填充到dto中
     *
     * @param dto          返回给前端的dto数据
     * @param orderAddress 订单的地址信息
     */
    private void fillFromAddress(OrdOrderDto dto, OrdOrderAddress orderAddress) {

        if (StringUtils.isEmpty(dto.getFromPhone()) && StringUtils.isEmpty(dto.getFromTelephone())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "发件人固定电话或手机号码不能全为空!");
        }

        if (dto.getFromAddress().getTransportType() <= 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "发件人地址类型异常!");
        }
        orderAddress.setFromTransportType(dto.getFromAddress().getTransportType());
        if (dto.getFromAddress().getTransportType() == CommCodes.TRANSPORT_AIR || dto.getFromAddress().getTransportType() == CommCodes.TRANSPORT_SEA) {
            if (dto.getFromAddress().getTransportId() <= 0) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "发件人运输工具类型异常");
            }
        }
        if ((dto.getFromAddress().getTransportType() == CommCodes.TRANSPORT_AIR
                || dto.getFromAddress().getTransportType() == CommCodes.TRANSPORT_SEA)
                && "CN".equalsIgnoreCase(dto.getFromAddress().getCountryCode())) {
            AreaDto areaDto = areaService.findByAreaId(dto.getFromAddress().getCityId(), dto.getFromAddress().getCountryCode());
            if (!ObjectUtils.isEmpty(areaDto)) {
                dto.getFromAddress().setProvinceId(areaDto.getParentId());
            }
        }
        orderAddress.setFromTransportId(dto.getFromAddress().getTransportId());
        orderAddress.setFromTransportType(dto.getFromAddress().getTransportType());
        orderAddress.setFromCountry(dto.getFromAddress().getCountryCode());
        orderAddress.setFromProvince(dto.getFromAddress().getProvinceId());
        orderAddress.setFromCity(dto.getFromAddress().getCityId());
        orderAddress.setFromDistrict(dto.getFromAddress().getDistrictId());
        orderAddress.setFromStreet(dto.getFromAddress().getStreetId());
        orderAddress.setFromAddress(dto.getFromAddress().getAddress());
        orderAddress.setFromPostcode(dto.getFromAddress().getPostcode());
        orderAddress.setFromEmail(dto.getFromAddress().getEmail());
        String addressDetail = this.processAddressDetail(dto.getFromName(), orderAddress.getFromTelephone(), dto.getFromAddress(), dto.getFromPhone());
        orderAddress.setFromDetail(addressDetail);
    }

    /**
     * 如果揽货地址没有添写的情况下，使用from中的地址信息
     *
     * @param dto
     */
    private void vaildFetchInfo(OrdOrderDto dto) {
        if (ObjectUtils.isEmpty(dto.getFetchAddress())) {
            OrderAddressModel fetchAddress = new OrderAddressModel();
            EntityUtils.copyPropertiesIgnoreNull(dto.getFromAddress(), fetchAddress);
            dto.setFetchAddress(fetchAddress);
        }
        if (StringUtils.isEmpty(dto.getFetchName())) {
            dto.setFetchName(dto.getFromName());
        }
        if (StringUtils.isEmpty(dto.getFetchPhone())) {
            dto.setFetchPhone(dto.getFromPhone());
        }
    }

    private String processAddressDetail(String name, String telephone, OrderAddressModel addressModel, String phone) {
        StringBuffer addressDetail = new StringBuffer();
        addressDetail.append((name == null ? "" : name) + "|");//名字
        addressDetail.append((telephone == null ? "" : telephone) + "|");//固定电话
        addressDetail.append((phone == null ? "" : phone) + "|");//手机号
        addressDetail.append((addressModel.getCountryName() == null ? "" : addressModel.getCountryName()) + "|");//国家
        addressDetail.append((addressModel.getProvinceName() == null ? "" : addressModel.getProvinceName()) + "|");//省
        addressDetail.append((addressModel.getCityName() == null ? "" : addressModel.getCityName()) + "|");//市
        addressDetail.append((addressModel.getDistrictName() == null ? "" : addressModel.getDistrictName()) + "|");//区
        addressDetail.append((addressModel.getStreetName() == null ? "" : addressModel.getStreetName()) + "|");//街道

        String transportTypeName;
        transportTypeName = addressModel.getTransportTypeName();
        if (StringUtils.isEmpty(transportTypeName)) {
            ProductGroup productGroup = productGroupService.findById(addressModel.getTransportType());
            if (!ObjectUtils.isEmpty(productGroup)) {
                transportTypeName = productGroup.getName();
            }
        }
        addressDetail.append(transportTypeName + "|");//运输类型的名字

        addressDetail.append((addressModel.getTransportName() == null ? "" : addressModel.getTransportName()) + "|");//运输方式
        addressDetail.append((addressModel.getAddress() == null ? "" : addressModel.getAddress()) + "|");//详细地址
        addressDetail.append((addressModel.getPostcode() == null ? "" : addressModel.getPostcode()) + "|");//邮编
        addressDetail.append((addressModel.getEmail() == null ? "" : addressModel.getEmail()));//邮编
        return addressDetail.toString();
    }

    /**
     * 客户只能修改草稿状态的订单
     *
     * @param oldOrder 原来的订单信息
     * @param orderDto 要保存的订单信息
     * @param userType 用户的类型  operator 运营人员  customer 客户
     */
    private void judgeOperate(OrdOrder oldOrder, OrdOrderDto orderDto, String userType) {
        //修改客户id时，要同时修改客户的账户id
        if (!orderDto.getCusUserId().equals(oldOrder.getCusUserId())) {
            CusUser cusUser = customerUserService.findShortById(orderDto.getCusUserId());
            if (ObjectUtils.isEmpty(cusUser) || ObjectUtils.isEmpty(cusUser.getRefCustomerId())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "客户id不存在");
            }
            orderDto.setCustomerId(cusUser.getRefCustomerId());
        }


        //1.客户系统入口-----检查是否是自己修改自己的订单,(自己不允许修改别人的订单)
        if (userType.equals(CommCodes.CUSTOMER)) {
            Integer currentUserId = PrincipalUtils.getAccountId();
            if (orderDto.getCusUserId().intValue() != currentUserId.intValue()) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "不能修改非自己的订单");
            }
        }


        //2、客户、产品、订单状态校验——如果订单不为草稿，那么客户的账户信息、账号信息、产品、订单状态的信息不允许修改
        if (OrderStatus.DRAFT != oldOrder.getOrderStatus()) {
            if (!orderDto.getCustomerId().equals(oldOrder.getCustomerId())
                    || !orderDto.getCusUserId().equals(oldOrder.getCusUserId())) {//客户信息不允许修改
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "非草稿状态下，客户信息不允许修改");
            }
            if (!oldOrder.getProductUid().equals(orderDto.getProductUid())) {// 产品信息不允许修改
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "非草稿状态下，不能修改产品信息");
            }

            if (!oldOrder.getOrderStatus().equals(orderDto.getOrderStatus())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单状态异常");
            }
        }
        //3、子件个数校验——已收货之后，不让修改子件个数
        if (oldOrder.getOrderStatus().compareTo(OrderStatus.RECEGOOD) >= 0) {
            if (oldOrder.getPackageNum().intValue() != orderDto.getPackageNum().intValue()) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "该订单状态为" + oldOrder.getOrderStatus().getName() + "不能修改子件的个数,你可以重新下单");
            }
        }
        //4、修改订单权限校验——当客户平台下单时，订单状态非草稿状态，不允许对订单做操作
        if (userType.equals(CommCodes.CUSTOMER) && oldOrder.getOrderStatus() != OrderStatus.DRAFT) {//客户
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "此订单当前状态已经不允许修改");
        }
    }


    /**
     * 判断可选服务的有效性
     *
     * @param additionalServiceUidList
     * @param productServiceRelList
     */
    private boolean judgeAddtional(List<String> additionalServiceUidList, List<ProductServiceRel> productServiceRelList) {
        boolean bOk = true;
        if (!CollectionUtils.isEmpty(additionalServiceUidList)) {
            List<String> productServiceUidList = new ArrayList<>();
            productServiceRelList.forEach(productServiceRel -> productServiceUidList.add(productServiceRel.getServiceUid()));

            //判断附加服务有效性
            //如果某个附加服务不在产品中，那么证明用户选的产品附加服务是有问题的
            if (!productServiceUidList.containsAll(additionalServiceUidList)) {
                bOk = false;
            }
        }
        return bOk;
    }

    /**
     * 向dto中设置地址信息
     *
     * @param orderDto     订单dto实体
     * @param orderAddress 订单实体
     * @param type
     */
    private void processAddress(OrdOrderDto orderDto, OrdOrderAddress orderAddress, int type) {
        //1、处理发件人地址
        OrderAddressModel fromAddress = new OrderAddressModel();
        fromAddress.setCountryCode(orderAddress.getFromCountry());
        fromAddress.setProvinceId(orderAddress.getFromProvince());
        fromAddress.setCityId(orderAddress.getFromCity());
        fromAddress.setDistrictId(orderAddress.getFromDistrict());
        fromAddress.setStreetId(orderAddress.getFromStreet());
        fromAddress.setTransportType(orderAddress.getFromTransportType());
        fromAddress.setTransportId(orderAddress.getFromTransportId());
        fromAddress.setAddress(orderAddress.getFromAddress());
        fromAddress.setPostcode(orderAddress.getFromPostcode());
        fromAddress.setEmail(orderAddress.getFromEmail());
        String addressDetail = orderAddress.getFromDetail();
        String[] address;
        if (StringUtils.hasLength(addressDetail)) {
            logger.info(addressDetail + "====" + orderDto.getOrderNo());
            address = addressDetail.split("\\|", -1);
            this.processAddressName(address, fromAddress);
            //海运
            if (orderAddress.getFromTransportType() == CommCodes.TRANSPORT_SEA) {
                Port port = portService.findShortById(orderAddress.getFromTransportId());
                if (!ObjectUtils.isEmpty(port)) {
                    fromAddress.setTransportName(port.getName());
                    fromAddress.setTransportCode(port.getCode());
                    fromAddress.setTransportEnglishName(port.getEnglishName());
                }
            } else if (orderAddress.getFromTransportType() == CommCodes.TRANSPORT_AIR) {
                //空运
                Airport port = airportService.findShortById(orderAddress.getFromTransportId());
                if (!ObjectUtils.isEmpty(port)) {
                    fromAddress.setTransportCode(port.getTriadCode());
                    fromAddress.setTransportName(port.getName());
                }
            }
            if (orderAddress.getFromTransportType() != null &&
                    orderAddress.getFromTransportType() != CommCodes.TRANSPORT_LAND &&
                    type == 2) {
                fromAddress.setCityName(fromAddress.getTransportName());
            }
        }
        orderDto.setFromAddress(fromAddress);
        orderDto.setFromName(orderAddress.getFromName());
        orderDto.setFromPhone(orderAddress.getFromPhone());
        orderDto.setFromTelephone(orderAddress.getFromTelephone());

        //2、处理取货地址
        if (!StringUtils.isEmpty(orderAddress.getFetchCountry())) {
            OrderAddressModel fetchAddress = new OrderAddressModel();
            fetchAddress.setCountryCode(orderAddress.getFetchCountry());
            fetchAddress.setProvinceId(orderAddress.getFetchProvince());
            fetchAddress.setCityId(orderAddress.getFetchCity());
            fetchAddress.setDistrictId(orderAddress.getFetchDistrict());
            fetchAddress.setStreetId(orderAddress.getFetchStreet());
            fetchAddress.setTransportType(orderAddress.getFetchTransportType() == null ? 0 : orderAddress.getFetchTransportType());
            fetchAddress.setTransportId(orderAddress.getFetchTransportId() == null ? 0 : orderAddress.getFetchTransportId());
            fetchAddress.setAddress(orderAddress.getFetchAddress());
            fetchAddress.setPostcode(orderAddress.getFetchPostcode());
            fetchAddress.setEmail(orderAddress.getFetchEmail());
            addressDetail = orderAddress.getFetchDetail();
            if (StringUtils.hasLength(addressDetail)) {
                logger.info(addressDetail + "====" + orderDto.getOrderNo());
                address = addressDetail.split("\\|", -1);
                this.processAddressName(address, fetchAddress);
                if (orderAddress.getFetchTransportType() != null && orderAddress.getFetchTransportType() != 11 && type == 2) {
                    fetchAddress.setCityName(fetchAddress.getTransportName());
                }
            }

            orderDto.setFetchAddress(fetchAddress);
            orderDto.setFetchName(orderAddress.getFetchName());
            orderDto.setFetchPhone(orderAddress.getFetchPhone());
            orderDto.setFetchTelephone(orderAddress.getFetchTelephone());
        }
        //3、处理收件人地址
        OrderAddressModel toAddress = new OrderAddressModel();
        toAddress.setCountryCode(orderAddress.getToCountry());
        toAddress.setProvinceId(orderAddress.getToProvince());
        toAddress.setCityId(orderAddress.getToCity());
        toAddress.setDistrictId(orderAddress.getToDistrict());
        toAddress.setStreetId(orderAddress.getToStreet());
        toAddress.setTransportType(orderAddress.getToTransportType());
        toAddress.setTransportId(orderAddress.getToTransportId());
        toAddress.setAddress(orderAddress.getToAddress());
        toAddress.setPostcode(orderAddress.getToPostcode());
        toAddress.setEmail(orderAddress.getToEmail());
        addressDetail = orderAddress.getToDetail();
        if (StringUtils.hasLength(addressDetail)) {
            logger.info(addressDetail + "====" + orderDto.getOrderNo());
            address = addressDetail.split("\\|", -1);
            this.processAddressName(address, toAddress);

            if (orderAddress.getToTransportType() == CommCodes.TRANSPORT_SEA) {
                Port port = portService.findShortById(orderAddress.getToTransportId());
                if (!ObjectUtils.isEmpty(port)) {
                    toAddress.setTransportName(port.getName());
                    toAddress.setTransportCode(port.getCode());
                    toAddress.setTransportEnglishName(port.getEnglishName());
                }

            } else if (orderAddress.getToTransportType() == CommCodes.TRANSPORT_AIR) {
                Airport port = airportService.findShortById(orderAddress.getToTransportId());
                if (!ObjectUtils.isEmpty(port)) {
                    toAddress.setTransportCode(port.getTriadCode());
                    toAddress.setTransportName(port.getName());
                }

            }
            if (orderAddress.getToTransportType() != null && orderAddress.getToTransportType() != CommCodes.TRANSPORT_LAND && type == 2) {
                toAddress.setCityName(toAddress.getTransportName());
            }
        }
        orderDto.setToAddress(toAddress);
        orderDto.setToName(orderAddress.getToName());
        orderDto.setToPhone(orderAddress.getToPhone());
        orderDto.setToTelephone(orderAddress.getToTelephone());
    }

    private void processAddressName(String[] address, OrderAddressModel addressModel) {
        if (address != null && address.length >= 11) {
            addressModel.setCountryName(address[3]);
            addressModel.setProvinceName(address[4]);
            addressModel.setCityName(address[5]);
            addressModel.setDistrictName(address[6]);
            addressModel.setStreetName(address[7]);
            addressModel.setTransportTypeName(address[8]);
            addressModel.setTransportName(address[9]);
            addressModel.setAddress(address[10]);
        } else {
            // throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "地址错误");
        }
    }


    /**
     * 此方法不需要事务
     *
     * @param orderNo
     */
    private void dealFeeCalcWeight(String orderNo) {
        QuotationCalcResult calcResult = calcService.calcWaybillFeeWeight(orderNo);
        if (!ObjectUtils.isEmpty(calcResult)) {
            OrdOrder ordOrder = new OrdOrder();
            ordOrder.setFeeCalcWeight(calcResult.getFeeWeight());
            ordOrder.setFeeCalcWeightUnit(calcResult.getFeeWeightUnitCode());
            ordOrder.setVolumeWeight(calcResult.getVolumeWeight());
            ordOrder.setVolumeWeightUnit(calcResult.getVolumeWeightUnitCode());
            ordOrder.setOrderNo(orderNo);
            this.update(ordOrder);
        }
    }

    /**
     * 校验订单有效性
     * 如果订单是保存为草稿状态，或者是保存为已经提交的状态，产品停用不能保存。
     * 如果订单时从草稿修改为提交状态，产品停用不能修改。
     * 如果订单从已经提交变为已经受理，产品停用不能更改。此判断不在这里处理.
     * 如果订单状态>=已经受理，不用管产品状态.
     *
     * @param ordOrder     订单的信息
     * @param orderAddress
     */
    private void validated(OrdOrder ordOrder, OrdOrderAddress orderAddress) {
        //1、产品有效性校验
        if (ordOrder.getOrderStatus() == OrderStatus.DRAFT || ordOrder.getOrderStatus() == OrderStatus.COMMITED) {
            //表示此时是保存
            Product product = productService.findShortActivedByUid(ordOrder.getProductUid());

            int fromTransportType = orderAddress.getFromTransportType();
            int toTransportType = orderAddress.getToTransportType();
            if (fromTransportType != toTransportType) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "收件人与发件人地址类型应保持一致！");
            }

            ProductGroupInfo productGroupInfo = productService.getProductGroupById(product.getId());
            if (null != productGroupInfo) {
                int rootId = productGroupInfo.getProductGroupRootId();
                if (rootId > 0) {
                    if (fromTransportType != CommCodes.TRANSPORT_LAND && fromTransportType != rootId) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "发件人地址类型异常");
                    }
                    if (toTransportType != CommCodes.TRANSPORT_LAND && toTransportType != rootId) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "收件人地址类型异常");
                    }
                    if (toTransportType == CommCodes.TRANSPORT_LAND || fromTransportType == CommCodes.TRANSPORT_LAND) {
                        if (rootId == CommCodes.TRANSPORT_AIR || rootId == CommCodes.TRANSPORT_SEA) {
                            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "地址类型与产品不匹配");
                        }
                    }
                }
            }

            if (ObjectUtils.isEmpty(product)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "产品不存在，请核查！");
            }
            if (!product.getIsOnline()) {//产品如果被审核，那么他状态一定为3，在状态为3的情况下，可能存在isonline上线或下线的问题，如果下线就不进行下单
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "产品未上线，请核查！");
            }
        }
        //2、客户有效性校验
        this.judgeCustomer(ordOrder);

        //3、货物类型有效性校验
        List<String> cargoTypeList = productCargoTypeRelService.findByProductUid(ordOrder.getProductUid());
        if (!cargoTypeList.contains(ordOrder.getCargoType())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "货物类型不支持！");
        }

        //4、重量范围有效性校验
        ResultDto resultDto = productService.checkWeight(ordOrder.getProductUid(), new WeightDto(ordOrder.getCusWeight(), ordOrder.getCusWeightUnit()));
        boolean isOk = (boolean) resultDto.getData();
        if (!isOk) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "订单重量不在指定范围内");
        }

        //5、地址有效性校验
        this.judgeAddress(ordOrder, orderAddress);
        //检验客户单号
        this.validateExternalNo(ordOrder);


    }

    /**
     * 客户系统的订单，需要校验订单外部关联号的唯一性
     *
     * @param ordOrder
     */
    private void validateExternalNo(OrdOrder ordOrder) {
        if (StringUtils.isEmpty(ordOrder.getExternalNo())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "客户单号不能为空");
        }
        int id = 0;
        if (ordOrder.getId() != null) {
            id = ordOrder.getId();
        }
        OrdOrder oldOrder = findByExternalNoAndCustomerId(ordOrder.getExternalNo(), ordOrder.getCustomerId(), id);
        if (!ObjectUtils.isEmpty(oldOrder)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "客户单号已经存在,每个用户的每个客户单号只能使用一次");
        }
    }

    /**
     * 客户的账户、账号有性性校验
     * 如果订单是保存为草稿状态，或者是保存为已经提交的状态，客户账号有问题不能保存。
     * 如果订单时从草稿修改为提交状态，客户账号有问题不能修改。
     * 如果订单从已经提交变为已经受理，客户账号有问题不能更改。此判断不在这里处理.
     * 如果订单状态>=已经受理，不用管客户状态
     *
     * @param ordOrder 订单信息
     */
    private void judgeCustomer(OrdOrder ordOrder) {
        if (ordOrder.getOrderStatus() == OrderStatus.DRAFT || ordOrder.getOrderStatus() == OrderStatus.COMMITED) {
            //账户有效性校验
            CusCustomer customer = customerService.findShortById(ordOrder.getCustomerId());
            if (ObjectUtils.isEmpty(customer)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "账户不存在！");
            }
            if (customer.getLocked() || customer.getDeleted()) {//客户的账户如果被锁定或被删除，不能下单
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "客户账户异常！");
            }
            //账号有效性校验
            CusUser cusUser = customerUserService.findShortById(ordOrder.getCusUserId());
            if (ObjectUtils.isEmpty(cusUser)) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "账号不存在！");
            }
            if (cusUser.getIsLocked() || cusUser.getIsDeleted()) {//客户的账号如果被锁定或被删除，不能下单
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "客户账号异常！");
            }
        }
    }

    /**
     * 收件人、发件人地址校验
     *
     * @param ordOrder     订单信息
     * @param orderAddress
     */
    private void judgeAddress(OrdOrder ordOrder, OrdOrderAddress orderAddress) {
        ResultDto resultDto;
        Map<String, Boolean> map;
        //发件人有效性校验


        //获取可选服务的uid集合
        List<ProductAddressDto> productAddressDtoList = productService.getProductAddress(ordOrder.getProductUid(), CommCodes.PRODUCT_SERVICE_REGION_START);
        ProductAddressDto productAddressDto = new ProductAddressDto();
        productAddressDto.setCountry(orderAddress.getFromCountry());
        productAddressDto.setProvince(orderAddress.getFromProvince());
        productAddressDto.setCity(orderAddress.getFromCity());
        productAddressDto.setArea(orderAddress.getFromDistrict());
        productAddressDto.setStreet(orderAddress.getFromStreet());
        productAddressDto.setTransportType(orderAddress.getFromTransportType());
        productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_START);
        productAddressDto.setTransportId(orderAddress.getFromTransportId());
        boolean isOk = productService.checkProductAddress(productAddressDtoList, productAddressDto);
        if (!isOk) {
            if (ordOrder.getType().intValue() == OrderConstants.OrderPlatform.ORDER_OPERATOR) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "始发地址不在产品可服务的范围内!");
            } else {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "始发地址不在产品可服务的范围内!");
            }
        }
        // }
        //收件人有效性校验

        productAddressDtoList = productService.getProductAddress(ordOrder.getProductUid(), CommCodes.PRODUCT_SERVICE_REGION_END);
        productAddressDto = new ProductAddressDto();
        productAddressDto.setCountry(orderAddress.getToCountry());
        productAddressDto.setProvince(orderAddress.getToProvince());
        productAddressDto.setCity(orderAddress.getToCity());
        productAddressDto.setArea(orderAddress.getToDistrict());
        productAddressDto.setStreet(orderAddress.getToStreet());
        productAddressDto.setTransportType(orderAddress.getToTransportType());
        productAddressDto.setAddressType(CommCodes.PRODUCT_SERVICE_REGION_START);
        productAddressDto.setTransportId(orderAddress.getToTransportId());
        isOk = productService.checkProductAddress(productAddressDtoList, productAddressDto);
        if (!isOk) {
            if (ordOrder.getType().intValue() == OrderConstants.OrderPlatform.ORDER_OPERATOR) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, CommCodes.FROM_ADDRESS_NOT_IN_SERVICE_SCOPE_OPERATION);
            } else {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, CommCodes.FROM_ADDRESS_NOT_IN_SERVICE_SCOPE_CUSTOMER);
            }
        }
    }


    private void processOrderRelationInfo(OrdOrderDto orderDto, OrdOrderAddress ordOrderAddress, int origPackageNum, OrderStatus origOrderStatus, OrdOrder order) {

        //1、更新订单的地址信息
        orderAddressService.update(ordOrderAddress);//根据主键id更新订单的地址信息

        //2、处理货物明细，删掉旧的获取明细，增加新的货物明细
        orderCargoService.saveCargoDtos(orderDto.getOrderNo(), orderDto.getProductUid(), orderDto.getOrderCargoDtos());

        //3、处理附加服务
        orderAdditionalService.deleteByOrderNo(orderDto.getOrderNo());
        this.processOptional(orderDto);

        //4、处理子单,只有提交订单后才会有子订单的概念
        if (OrderStatus.COMMITED.compareTo(orderDto.getOrderStatus()) <= 0) {
            this.updateSubOrder(order, origPackageNum, origOrderStatus);

        }
    }

    /**
     * 修改订单时，修改子单数据,认为只要子单发生变化，那么相应的物流也要有变化
     * 1. 判断子单数量是否改变，如果改变，删掉之前的子单数据，增加新的子单数据
     *
     * @param order
     * @param origPackgeNum
     * @param origOrderStatus
     */
    private void updateSubOrder(OrdOrder order, int origPackgeNum, OrderStatus origOrderStatus) {
        boolean isUpdate = false;
        if (origPackgeNum != order.getPackageNum()
                || (origOrderStatus == OrderStatus.DRAFT && order.getOrderStatus() != OrderStatus.DRAFT)) {
            subOrderService.saveSubOrders(order.getOrderNo(), order.getWaybillNo(), order.getPackageNum(), order.getOrderStatus());
            isUpdate = true;
        }

        if (origOrderStatus.compareTo(order.getOrderStatus()) != 0) {
            //更新子订单的状态
            List<String> subOrderNos = subOrderService.getSubOrdNos(order.getOrderNo());
            subOrderService.updateOrderStatus(subOrderNos, order.getOrderStatus());
            isUpdate = true;
        }

        if (isUpdate) {
            List<String> subOrderNos = subOrderService.getSubOrdNos(order.getOrderNo());
            this.processTrackings(order.getOrderStatus(), order.getOrderNo(), order.getWaybillNo(), subOrderNos);
        }
    }


    /**
     * 处理子单对应的物流信息
     *
     * @param orderStatus 订单的状态
     * @param orderNo     订单编号
     * @param waybillNo
     * @param subOrderNos 子订单集合
     */
    private void processTrackings(OrderStatus orderStatus, String orderNo, String waybillNo, List<String> subOrderNos) {
        if (!CollectionUtils.isEmpty(subOrderNos)) {
            subOrderService.batchAddSubTracking(orderNo, waybillNo, orderStatus, subOrderNos);
        }
    }

    private void updateOrderStatus(List<String> orderNoList, OrderStatus orderStatus) {
        if (!CollectionUtils.isEmpty(orderNoList)) {
            Map<String, OrderStatus> processOrderMap = new HashMap<>();
            for (String orderNo : orderNoList) {
                processOrderMap.put(orderNo, orderStatus);
            }
            this.updateOrderStatus(processOrderMap);
        }
    }


    @Override
    public OrdOrderFeePayDto findOrderFeeInfo(String orderNo) {
        OrdOrderFeePayDto ordOrderFeePayDto = null;
        //暂时先用运单号 orderNo代替orderNo
        OrdOrder ordOrder = this.findByOrderNo(orderNo);
        OrdOrderFee ordOrderFee = orderFeeService.findByOrderNo(orderNo);
        if (!ObjectUtils.isEmpty(ordOrderFee)) {
            ordOrderFeePayDto = new OrdOrderFeePayDto();
            EntityUtils.copyPropertiesIgnoreNull(ordOrderFee, ordOrderFeePayDto);
            ordOrderFeePayDto.setOrderStatusName(ordOrder.getOrderStatus().getName());
            if (ordOrder.getPayStatus() != null) {
                ordOrderFeePayDto.setPayStatusName(ordOrder.getPayStatus().getName());
            }

            if (null == ordOrder.getSettlementTypeId()) {
                ordOrderFeePayDto.setCashCustormer(false);
                return ordOrderFeePayDto;
            }
            if (CommCodes.CASH_PAID == ordOrder.getSettlementTypeId()) {
                ordOrderFeePayDto.setCashCustormer(true);
            } else {
                ordOrderFeePayDto.setCashCustormer(false);
            }
        }

        return ordOrderFeePayDto;
    }


    /**
     * 根据运单号查询运单号、订单号的map
     *
     * @param waybillNos 运单号集合
     * @return 运单号、订单号的map
     */
    @Override
    public Map<String, String> findNoMapByWaybillNos(List<String> waybillNos) {
        Map<String, String> orderNoMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(waybillNos)) {
            ParamData pd = new ParamData();
            pd.put("waybillNos", waybillNos);
            List<OrdOrder> ordOrderList = dao.findForList(getSqlName("findNoMapByWaybillNos"), pd, OrdOrder.class);
            if (!CollectionUtils.isEmpty(ordOrderList)) {
                ordOrderList.forEach(ordOrder -> orderNoMap.put(ordOrder.getWaybillNo(), ordOrder.getOrderNo()));
            }
        }
        return orderNoMap;
    }

    /**
     * 根据运单号获取订单号集合
     *
     * @param waybillNos 运单号集合
     * @return 订单号集合
     */
    @Override
    public List<String> findOrderNosByWaybillNos(List<String> waybillNos) {
        List<String> orderNos = new ArrayList<>();
        Map<String, String> waybillNoOrderNoMap = this.findNoMapByWaybillNos(waybillNos);
        if (!CollectionUtils.isEmpty(waybillNoOrderNoMap)) {
            orderNos.addAll(waybillNoOrderNoMap.values());
        }
        return orderNos;
    }

    /**
     * 根据运单号查询订单号
     *
     * @param waybillNo 运单号
     * @return 订单号
     */
    @Override
    public String findOrderNoByWaybillNo(String waybillNo) {
        String orderNo = "";
        List<String> orderNos = this.findOrderNosByWaybillNos(Arrays.asList(waybillNo));
        if (!CollectionUtils.isEmpty(orderNos)) {
            orderNo = orderNos.get(0);
        }
        return orderNo;
    }


    /**
     * 根据订单号查询订单号、运单号的map
     *
     * @param orderNos 订单号集合
     * @return 订单号、运单号的map
     */
    @Override
    public Map<String, String> findNoMapByOrderNos(List<String> orderNos) {
        Map<String, String> orderNoMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(orderNos)) {
            ParamData pd = new ParamData();
            pd.put("orderNos", orderNos);
            List<OrdOrder> ordOrderList = dao.findForList(getSqlName("findNoMapByOrderNos"), pd, OrdOrder.class);
            if (!CollectionUtils.isEmpty(ordOrderList)) {
                ordOrderList.forEach(ordOrder -> orderNoMap.put(ordOrder.getOrderNo(), ordOrder.getWaybillNo()));
            }
        }
        return orderNoMap;
    }

    /**
     * 根据订单号查询运单号集合
     *
     * @param orderNos 订单号集合
     * @return 运单号集合
     */
    @Override
    public List<String> findWaybillNosByOrderNos(List<String> orderNos) {
        List<String> waybillNos = new ArrayList<>();
        Map<String, String> orderWaybillNoMap = this.findNoMapByOrderNos(orderNos);
        if (!CollectionUtils.isEmpty(orderWaybillNoMap)) {
            waybillNos.addAll(orderWaybillNoMap.values());
        }
        return waybillNos;
    }

    @Override
    public String findWaybillNoByOrderNo(String orderNo) {
        String waybillNo = "";
        List<String> waybillNos = this.findWaybillNosByOrderNos(Arrays.asList(orderNo));
        if (!CollectionUtils.isEmpty(waybillNos)) {
            waybillNo = waybillNos.get(0);
        }
        return waybillNo;
    }

    @Override
    public void payOrder(String orderNo) {
        OrdOrder order = new OrdOrder();
        order.setOrderNo(orderNo);
        order.setPayStatus(PayStatus.PAID);
        this.update(order);

        //this.sendOutgoingMessage(orderNo);
    }

    @Override
    public void sendOutgoingMessage(String orderNo) {
        List<CsrWorkOrderSchema> workOrderSchemaList = workOrderSchemaService.queryBlockByOrderNo(orderNo);
        OrdOrder order = this.findByOrderNo(orderNo);
        if (CollectionUtils.isEmpty(workOrderSchemaList) && PayStatus.PAID == order.getPayStatus()) {
            this.sendOutgoingTracking(orderNo);
        }
    }

    /**
     * 根据订单号查询订单选择的服务信息
     *
     * @param orderNo 订单号
     * @param bOk
     * @return 服务信息详情
     */
    @Override
    public List<OrdOrderServiceInfoDto> findOrderServiceInfo(String orderNo, boolean bOk) {
        List<OrdOrderServiceInfoDto> serviceInfoList = new ArrayList<>();
        if (!StringUtils.isEmpty(orderNo)) {
            //从服务匹配表中找到匹配的信息
            List<OrdOrderOptionService> optionServiceList = orderServiceAssignService.findOrderServiceByOrderNo(orderNo, bOk);
            for (OrdOrderOptionService optionService : optionServiceList) {
                OrdOrderServiceInfoDto serviceInfo = new OrdOrderServiceInfoDto();
                EntityUtils.copyPropertiesIgnoreNull(optionService, serviceInfo);
                this.processServiceInfo(serviceInfo, optionService);
                serviceInfoList.add(serviceInfo);
            }
        }
        return serviceInfoList;
    }


    private void processServiceInfo(OrdOrderServiceInfoDto serviceInfo, OrdOrderOptionService optionService) {
        Service service = serviceService.findById(optionService.getServiceId());
        if (!ObjectUtils.isEmpty(service)) {
            serviceInfo.setServiceName(service.getName());
            serviceInfo.setServiceCode(service.getCode());

            Supplier supplier = supplierService.findSimpleById(service.getSupplierId());
            if (!ObjectUtils.isEmpty(supplier)) {
                serviceInfo.setSupplierCode(supplier.getCode());
                serviceInfo.setSupplierName(supplier.getName());
                serviceInfo.setSupplierId(supplier.getId() == null ? 0 : supplier.getId());
            }
        }
        Map<String, String> serviceTypeMap = dictService.findMapByCatalog("biz.service.type");
        serviceInfo.setServiceTypeName(serviceTypeMap.get(serviceInfo.getServiceTypeCode()));

        Map<String, String> servicePropertyMap = dictService.findMapByCatalog("biz.product.serives.property");
        serviceInfo.setServicePropertyName(servicePropertyMap.get(serviceInfo.getServicePropertyCode()));
    }


    public static List<String> extractMessageByRegular(String msg) {
        List<String> list = new ArrayList<>();
        Pattern pattern = Pattern.compile(REGEX);
        Matcher m = pattern.matcher(msg);
        while (m.find()) {
            list.add(m.group().substring(1, m.group().length() - 1));
        }
        return list;
    }

    @Override
    public List<OrderDetail> getOrders() {
        Jedis jedis = RedisPoolManager.getJedis();
        byte[] cacheList = jedis.hget("orderDetails".getBytes(),"log".getBytes());
        jedis.close();
        if(cacheList!=null && cacheList.length>0){
            return (List)SerializeUtil.unserialize(cacheList);
        }
        else{
            ParamData pd = new ParamData();
            List<OrderDetail> list = new ArrayList<OrderDetail>();
            List<OrderDetail> orderDetails = dao.findForList(getSqlName("findOrders"), pd, OrderDetail.class);
            if (orderDetails != null) {
                for (OrderDetail orderDetail : orderDetails) {
                    OrderDetail newOrder = new OrderDetail();
                    EntityUtils.copyPropertiesIgnoreNull(orderDetail, newOrder);
                    OrdOrderAddress ordOrderAddress= orderAddressService.findByOrderNo(orderDetail.getOrderNo());
                    AreaDto from=areaService.findByAreaId(ordOrderAddress.getFromCity(),ordOrderAddress.getFromCountry());
                    AreaDto to=areaService.findByAreaId(ordOrderAddress.getToCity(),ordOrderAddress.getToCountry());
                    newOrder.setFromName(from.getName());
                    newOrder.setToName(to.getName());
                    list.add(newOrder);
                }
                jedis.del("orderDetails");

                //增加页面跳转之间的非法判断字段，存入redis中，超时则自动删除
                jedis.hset("orderDetails".getBytes(),"log".getBytes(), SerializeUtil.serialize(list));
                jedis.expire("orderDetails" , com.sz.biz.logistics.constants.OrderConstants.ORDER_CACHE_TIMEOUT);
                jedis.close();
            }
            return list;
        }
    }
}
